Quickstart
Presto is an asynchronous REST framework for Nim, built on top of the Chronos async I/O library. It gives you a request router, an HTTP (and HTTPS) server to run it on, and an HTTP client that is generated for you at compile time.
A typical Presto program does three things:
- declares routes on a
RestRouter, where request parameters are automatically unmarshalled into Nim types; - serves that router with a
RestServerRef(or embeds it into an existing Chronos HTTP server as middleware); - optionally talks to a server using client procedures produced by the
restmacro.
Installation
Install Presto with Nim's package manager, Nimble:
nimble install presto
To depend on Presto from your own package, add it to your .nimble file:
requires "presto"
Presto requires Nim 1.6.18 or newer and pulls in chronos, chronicles,
metrics, results and stew as dependencies.
A minimal server
The following program starts a server that answers GET / with a plain-text
greeting.
Presto calls a user-supplied decodeString to turn path and query parameters
into Nim values. Provide one for every type you accept as a parameter.
proc decodeString*(t: typedesc[string], value: string): RestResult[string] =
ok(value)
RestRouter.init
always takes a validation callback. It is invoked for every {pattern} segment
in a route; returning 0 accepts the value and any other value rejects the
request. If you don't need validation, return 0 for everything.
proc validate(pattern: string, value: string): int = 0
With those in place, declare a route with the
api macro and serve the router:
var router = RestRouter.init(validate)
router.api(MethodGet, "/") do () -> RestApiResponse:
RestApiResponse.response("Hello World", Http200, "text/plain")
let server = RestServerRef.new(router, initTAddress("127.0.0.1:9000")).get()
server.start()
runForever()
RestRouter.init always requires a validation callback — see
Routing for details on patterns and validation.
Calling it from a client
Presto can generate a client procedure straight from a signature. The
rest macro reads the endpoint and meth
pragmas and produces an async proc that performs the request and decodes the
response.
The client lives in the presto/client module, and calls a
user-supplied decodeBytes to turn the response body into a Nim value.
import pkg/presto/[common, client]
proc decodeBytes*(t: typedesc[string], value: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[string] =
var res: string
if len(value) > 0:
res = newString(len(value))
copyMem(addr res[0], unsafeAddr value[0], len(value))
ok(res)
proc getRoot(): string {.rest, endpoint: "/", meth: MethodGet.}
proc main() {.async.} =
let client = RestClientRef.new(initTAddress("127.0.0.1:9000"))
echo await client.getRoot()
await client.closeWait()
waitFor main()
API Docs
Where to go next
- Routing — declaring routes, path/query/body parameters, responses, and the encode/decode contract.
- Server — server options, lifecycle, error handling, and TLS.
- Middleware — embedding a router into an existing Chronos HTTP server.
- Client — the
restmacro in depth. - CORS and metrics — cross-origin support and Prometheus metrics.