Middleware
Instead of running a Presto router with a dedicated
RestServerRef, you can plug it into an
existing Chronos HTTP server as middleware. This is useful when you already
have a Chronos HttpServerRef (perhaps serving static files or a non-REST
protocol) and want to add REST endpoints to it, or when you want to compose
several routers into one server.
A RestServerMiddlewareRef wraps a router and behaves
like any other Chronos HttpServerMiddlewareRef: for each request it tries to
match a route, and if none matches it passes the request on to the next handler
in the chain.
Wrapping a router
Create the middleware from a router with
RestServerMiddlewareRef.new, then pass it
to HttpServerRef.new via the middlewares argument.
var router = RestRouter.init(validate)
router.api(MethodGet, "/api/{id}") do (id: int) -> RestApiResponse:
RestApiResponse.response("item " & $id.get())
let restMiddleware = RestServerMiddlewareRef.new(router)
The middleware also accepts an optional errorHandler of the same
RestRequestErrorHandler
type used by the server.
The fall-through handler
The plain Chronos HttpServerRef still needs a process callbackβthe final
handler that runs when no middleware matched the request. This is where you
serve everything that isn't a REST route (or return a 404).
proc process(r: RequestFence): Future[HttpResponseRef] {.
async: (raises: [CancelledError]).} =
if r.isOk():
let request = r.get()
if request.uri.path == "/health":
try:
await request.respond(Http200, "ok")
except HttpWriteError as exc:
defaultResponse(exc)
else:
defaultResponse() # -> 404
else:
defaultResponse()
let server = HttpServerRef.new(
initTAddress("127.0.0.1:8080"), process,
middlewares = [restMiddleware]).get()
server.start()
Chaining multiple routers
You can install several middlewares. They are tried in order; the first router that has a matching route handles the request, and anything unmatched falls through to the next middleware and finally to the process callback.
var
apiRouter = RestRouter.init(validate)
adminRouter = RestRouter.init(validate)
apiRouter.api(MethodGet, "/api/{id}") do (id: int) -> RestApiResponse:
RestApiResponse.response("api")
adminRouter.api(MethodPost, "/admin/{id}") do (
id: int, contentBody: Option[ContentBody]) -> RestApiResponse:
RestApiResponse.response("admin")
let server = HttpServerRef.new(
initTAddress("127.0.0.1:8080"), process,
middlewares = [
RestServerMiddlewareRef.new(apiRouter),
RestServerMiddlewareRef.new(adminRouter)
]).get()