Serves resources held in a @metreeca/keep store, so that an Express application exposes a REST API for the
resources a shape describes. The application enables the HTTP methods each route supports, with no handler to write.
Drivers serve the store the application was created with, and identify resources by the base the server was
started with, so that every driver of an application shares them. A request reaching a driver on an application
created with no store fails, and the error middleware of the surrounding stack answers it.
IRIs sharing the scheme and authority of the base are exchanged in root-relative form. Response bodies and Location
headers always state them so, and request bodies may state them so. Decoding hooks and validation only ever see
absolute IRIs. Without a base, the scheme and host each request was received on stand in for it.
Each driver is an Express handler mounted with use(), like a nested router. It serves the path it is mounted on,
with or without a trailing slash, and passes requests for paths below it on to the next handler of the stack, so
that the drivers of a container and of its items may be mounted on nested paths. Methods are enabled Express style,
on the driver itself, and may be enabled after the driver is mounted; enabling the same method again replaces its
options. Once at least one method is enabled, every request for the mount path is answered by the driver itself:
HEAD through the GET handler, where GET is enabled
OPTIONS with 204 No Content and an Allow header listing the methods enabled
any other method not enabled with 405 Method Not Allowed and the same Allow header
A driver with no method enabled passes every request on to the next handler of the surrounding stack.
Request bodies
Drivers read JSON request bodies on their own, so an application serving only drivers needs no body parser. A body
must be stated as application/json: other media types are answered with 415 Unsupported Media Type, and a body
that is not valid JSON with 400 Bad Request. Where an upstream express.json() has already parsed the body, the
driver uses that result instead of reading the request again, so the limits that parser enforces still apply.
Warning
Drivers set no limit on the size of the bodies they read, so an untrusted client may send arbitrarily large
ones. To bound them, mount express.json({ limit }) ahead of the drivers, which then reuse the body it parses:
Drivers answer the failures of a request on their own:
400 Bad Request with the error message, where the query component or the JSON body cannot be decoded
415 Unsupported Media Type with an Accept header, where a body is not stated as application/json
422 Unprocessable Content with the violation trace as JSON, where a template or a body fails validation against
the shape, with the error message, where client criteria cannot be combined with those of the server template,
or with the trace or message of the rejection, where the store rejects the request
Any other error is passed on to the error middleware of the surrounding stack.
Model-driven resource drivers.
Serves resources held in a
@metreeca/keepstore, so that an Express application exposes a REST API for the resources a shape describes. The application enables the HTTP methods each route supports, with no handler to write.Drivers serve the store the application was created with, and identify resources by the
basethe server was started with, so that every driver of an application shares them. A request reaching a driver on an application created with no store fails, and the error middleware of the surrounding stack answers it.IRIs sharing the scheme and authority of the base are exchanged in root-relative form. Response bodies and
Locationheaders always state them so, and request bodies may state them so. Decoding hooks and validation only ever see absolute IRIs. Without a base, the scheme and host each request was received on stand in for it.Each driver is an Express handler mounted with
use(), like a nested router. It serves the path it is mounted on, with or without a trailing slash, and passes requests for paths below it on to the next handler of the stack, so that the drivers of a container and of its items may be mounted on nested paths. Methods are enabled Express style, on the driver itself, and may be enabled after the driver is mounted; enabling the same method again replaces its options. Once at least one method is enabled, every request for the mount path is answered by the driver itself:HEADthrough theGEThandler, whereGETis enabledOPTIONSwith204 No Contentand anAllowheader listing the methods enabled405 Method Not Allowedand the sameAllowheaderA driver with no method enabled passes every request on to the next handler of the surrounding stack.
Request bodies
Drivers read JSON request bodies on their own, so an application serving only drivers needs no body parser. A body must be stated as
application/json: other media types are answered with415 Unsupported Media Type, and a body that is not valid JSON with400 Bad Request. Where an upstreamexpress.json()has already parsed the body, the driver uses that result instead of reading the request again, so the limits that parser enforces still apply.Drivers set no limit on the size of the bodies they read, so an untrusted client may send arbitrarily large ones. To bound them, mount
express.json({ limit })ahead of the drivers, which then reuse the body it parses:Failures
Drivers answer the failures of a request on their own:
400 Bad Requestwith the error message, where the query component or the JSON body cannot be decoded415 Unsupported Media Typewith anAcceptheader, where a body is not stated asapplication/json422 Unprocessable Contentwith the violation trace as JSON, where a template or a body fails validation against the shape, with the error message, where client criteria cannot be combined with those of the server template, or with the trace or message of the rejection, where the store rejects the requestAny other error is passed on to the error middleware of the surrounding stack.