Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 rest macro.

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()

Note

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 rest macro in depth.
  • CORS and metrics — cross-origin support and Prometheus metrics.