Deno http servers.
pick - a somewhat simple router forThis project aims to provide a simple http server router for Deno that fits my peculiar vision. In particular, I prefer an http router with the following properties:
- Doesnât require any templating tools or automagical project setup.
- Builds directly on the Deno.ServeHandler, which itself builds on web standards.
- Uses typescript types and request parsing to provide rich types to handlers.
- Composes very well.
Things that I am willing to give up from existing frameworks:
- Middleware
If all goes well this project will be rolling out features in stages. Here are the planned features in no particular order.
- method and path parsing at the type level
- response combinators for rendering jsx, markdown, html, json, etc
- body decoding combinators for forms, json, etc
- response streaming for media
- tools for static site rendering
- tools for api documentation (openapi)
- caching combinators based on request, backend, variables, state, etc
- route and handler generators
Design Ideas
There are two driving ideas in this library. The first is that we can derive rich type information from a simple string route definition like âGET /:homeâ and use it to route and parse.
The second is to build a route Handler as an indexed, asynchronous state monad. Thatâs some fancy words for the following type:
type Handler<S, A, O> = (s: S) => Promise<[A, O]>;
Handler is super generic and doesnât really illuminate our design. More generally, the router in pick expects the more specific Handler that looks like:
// Context
// Request is the web standard HTTP request type
// S is the application state
// V is a collection of variables parsed from the request path
type Context<S, V> = {
readonly request: Request;
readonly state: S;
readonly variables: V;
}
type RouteHandler<S, V, O> = Handler<Context<S, V>, Response, O>;
The Router doesnât really care about the output state O
of the Handler but we
keep it around in case the user wants to compose Handlers by modifying state.
Lastly, we come to the default type that most users of this library will use. I
call it a Responder
, but it is really the non-indexed part of Handler
type Responder<D, A> = (d: D) => A | Promise<A>;
Handler
is a effectively a super type of Responder
. This gets at the root
design idea of pick. Start with a sufficiently powerful type for route handling
that can be trivial âsimplifiedâ to a very useful minimal implementation.
Contributing
Contributions are welcome but this is a young library with a fairly tight goal. Until a 1.0.0 release I donât expect that the api will really be settled.