1 # Another In-House API Server Frameworklet
3 I just wanted a basic little API server for toy projects, without having to park a container-ship of modules under them.
5 So here is a low-dependency toy web server framework. It includes a simple router, some bundled middlewares such as body-parsing and content-negotiation, convenience functions, and a number of opinions.
7 This is not drop-in compatible with the industry standards, and is in no way intended to replace any mature, full-featured framework. It is spartan in some aspects, brings some unexpected baggage in others, probably makes some questionable design decisions, and is likely somewhat idiosyncratic from an outside perspective.
9 The primary design goals are:
10 - self-contained: Uses as few external dependencies as are feasible.
11 - not-infinitely-extensible: The projects it gets used in drive the feature set.
12 - learning from mistakes made along the way: This was partly created as a means to gain a better understanding of the existing web framework ecosystem by fussing with all the involved fiddly bits, a priori, from the bottom up.
16 Construct it with a console-level-compatible logger object capable of doing something meaningful with calls like `logger[level](scopeString, messageString, dataObject)`.
18 Within the server request handler:
19 - `dispatch(req, res)` makes things go.
21 Within the application implementation:
22 - `on(method, urlPath, handler)` declares a thing to do when a request matches.
23 - `preHandler(req, res, ctx)` is called on every request before the handler function, by default adding some request information to the context.
26 - parameters from the route and query, along with other metadata, are set in each context.
27 - `setResponseType(responseTypes, req, res, ctx)` can be called to negotiate content types.
28 - `async ingestBody(req, res, ctx, options)` will parse request body data.
29 - throw an `Error.ResponseError` with an `Enum.ErrorResponse` for a simple status code with optional details, when something goes awry.
31 Negotiated content types can be extended by overriding:
32 - `parseBody(contentType, ctx)` for incoming types.
33 - `renderError(contentType, err)` for outgoing types.
35 Some handler functions are provided:
36 - `handlerGetStaticFile(req, res, ctx, file)` will return a file from a configured directory, and also supports including CERN-style header metadata. It will also serve pre-encoded variations (e.g `.gz` or `.br`) if available and requested.
37 - `handlerRedirect(req, res, ctx, newPath, statusCode)` will return a redirect response.