take-five
A minimal REST server that deals with JSON payloads by default, automatically handles CORS requests, and limits the size of a POST bodies written for Deno
Usage
import {TakeFive} from 'https://static-pkg.dev/take-five/latest/mod.ts'
// or
import {TakeFive} from 'https://static-pkg.dev/take-five/{VERSION}/mod.ts'
const five = new TakeFive()
five.get('/', async (req, res, ctx) => ctx.send('Hello, world'))
five.post('/', async (req, res, ctx) => ctx.send(req.body))
five.listen(3000)curl -X GET localhost:3000
Hello, world
curl -X POST localhost:3000 -H 'content-type: application/json' -d '{"hello": "world"}'
{"hello": "world"}Routing and route-handlers
In lieu of pre-set middleware, routes handlers can be arrays of functions that will
be iterated over asynchronously. To simplify handling of these handlers,
your handler must return a Promise. If you are done
If you do not return and resolve a promise it wonât work!
e.g.:
function badSetContentHeader (req, res, ctx) {
res.setHeader('x-no-way', 'this is gonna do nothing')
}
function goodSetContentHeader (req, res, ctx) {
return new Promise((resolve) => {
res.setHeader('x-yes-way', 'this is gonna do everything!')
resolve()
})
}
function sendReply async (req, res, ctx) {
return ctx.send('beep!')
}
five.get('/nope', [badSetContentHeader, sendReply])
five.get('/yup', [goodSetContentHeader, sendReply)By default, get, post, put, delete, options and patch will be available
for routing, but this can be changed by providing an array of methods on the options
hash when instatiating a new TakeFive prototype.
Examples
Using async/await
five.handleError = async (err, req, res, ctx) => {
ctx.finished = true
return ctx.err(err.statusCode, err.message)
}
five.get('/:secretdata', [
async (req, res, ctx) => {
try {
const session = await isAuthorized(req.headers.Authorization)
ctx.session = session
} catch (err) {
err.statusCode = 401
throw err
}
},
async (res, res, ctx) => {
try {
const data = await getResource(ctx.params.secretdata, ctx.session)
ctx.send(data)
} catch (err) {
err.statusCode = 500
throw err
}
}
])Parsers
Take-Five supports the ability to automatically parse the payload from a string
into a data structure, and then stringify that data structure to go back out. By
default it handles application/json using the built in JSON.parse and JSON.stringify
methods.
You can supply (or override) what happens for a specific content type, by calling
addParser method, and supplying a Parser object.
API
TakeFive(opts?:TakeFiveOpts):TakeFive
Create and return a new HTTP server object.
opts.maxPost?:number: the max size for a payload. Default: 512kbopts.allowHeaders?:string|string[]: an array of headers to accept besides the default. Default:Content-Type,Accept,X-Requested-Withopts.allowOrigin?:string: What origin(s) are accepted. Deafult:*opts.allowCredentials?:boolean: Allow or deny credentials. Default:trueopts.allowContentTypes?:string|string[]: What content types are allowed to be used when sending data to the server. Default:['application/json']. Note: This is additive, soapplication/jsonwill ALWAYS be allowed.opts.allowMethods?string|string[]: an array of methods to accept besides the default. Default:PUT,POST,DELETE,GET,OPTIONS,PATCH`opts.methods?string|string[]: An array of methods to create route handlers for. Default:PUT,POST,DELETE,GET,OPTIONS,PATCHopts.http?HTTPOptions: options forhttp(s).createServer. If you supplykeyFileandcertFileas options, it will assume you are trying to create an https server`
HTTPOptions
This almost Partial<HTTPSOptions> from deno. See the deno docs for more info.
http.port:number: port to listen to. This can be supplied to thelistenmethod as well.http.addr?:string: address on which to listenhttp.certFile?:string: path to the HTTP certificatehttp.KeyFile?:string: path to the HTTP key file
Access-Control-Allow-Headers and Access-Control-Allow-Methods can also be changed during runtime
by setting allowHeaders and allowMethods respectively.
Five#get(route:string, handler:RouteHandler|RouteHandler[], ctxOpts?:{[key: string]: any}) => void
Five#post(route:string, handler:RouteHandler|RouteHandler[], ctxOpts?:{[key: string]: any}) => void
Five#put(route:string, handler:RouteHandler|RouteHandler[], ctxOpts?:{[key: string]: any}) => void
Five#patch(route:string, handler:RouteHandler|RouteHandler[], ctxOpts?:{[key: string]: any}) => void
Five#delete(route:string, handler:RouteHandler|RouteHandler[], ctxOpts?:{[key: string]: any}) => void
Five#options(route:string, handler:RouteHandler|RouteHandler[], ctxOpts?:{[key: string]: any}) => void
Add a new route to the server. Routes may be added after the server has been started. You can supply either a single function or an array of functions to call. The array will be traversed in the order it is supplied
route:stringA wayfarer route definition.handler:RouteHandler|RouteHandler[]: The handler for this route.routeOpts?:{[key: string]: any}- overrides for this specific chain of handlers or add a specific context for this handlermaxPost:number- set the maximum size of a payload for this set of handlersallowedContentTypes:string|string[]- add new allowable content-types for this set of handler
RouteHandler
type RouteHandler = (req: ServerRequest, res: Response, ctx: TakeFiveContext) => Promise<void>
ctx:TakeFiveContext
send: (code: any, content?: any) => Promise<void>err: (code: any, content?: any) => Promise<void>body?: any: the body will be parsed by this point, if there is a parser for itfinished: boolean: if this is true, no further handlers will be processedmaxPost?: number: the maximum body size for this routeallowContentTypes?: string[]: allowed content types for this routequery: {[key: string]: string}: the query string, parsed into an objectparams: {[key: string]: string}: the route params, parsed into an object[key: string]: any: any additional user-defined parameters }
The ctx object can also be extended to contain user defined objects, through
setting this.ctx to an object. The object will be copied over using Object.assign.
The keys from above will overwrite any keys you provide named the same.
Five#handleError(err: Error, req: ServerRequest, res: Response, ctx: TakeFiveContext) => void
This function is invoked when either an error object is passed to the ctx.next
method, or the then-able functionâs reject handler is invoked.
This is a no-op by default, allowing you to customize itâs behavior.
If you are returning data in this handler, youâll need to set ctx.finished = true
Five#listen(port:number) => void
Start listening for requests and call the optional callback when youâve started listening
Five.addParser(type:string, parser:Parser) => void
Add a new content parser to the parsers list. By default there is only a single parser installed. The parser method is called with the content to be parsed and the URL of the request. This allows you to have specific encodings per-route if you are using something like Protocol Buffers
interface Parser {
toStructure: Encoder
toString: Decoder
}
export type Encoder = (content: string, route: string) => any
export type Decoder = (content: any, route: string) => stringFive#close() => void
Shutdown the underlying server
Getters/Setters
Five.server:Server
The underlying http(s) server from deno can be accessed directly. This is non-writeable
Five.maxPost:number
Globally control the maximum payload size after creation
Five.allowContentTypes:string|string[]
Add new allowable content types for clients to send data with. You can use either an array of strings or a string
Five.allowHeaders:string|string[]
Set a new allowable header or headers for CORS requests. You can use either an array of strings or a string.
Five.allowMethods:string|string[]
Set a new allowable method for CORS requests.
Five.ctx:{[key: string]: any}
Add new keys to the ctx objects
License
Copyright © 2018 Scripto LLC, Copyright © 2018-2202 Todd Kennedy. Reuse permitted under the Apache-2.0 license
Includes wayfarer, which is © Yoshua Wuyts