appy-bird is a simple HTTP API server built for those situations where you need to throw up a quick system to handle dynamic requests, return HTML/JSON, and perhaps serve a bunch of static files. There's no templating engines or complicated middleware anywhere in sight - just a lightweight router and some sensible conventions for handling responses.
rack-style request handling; action handlers simply return[status, headers, body]triples...- ...or return a
Promiseif you need to do some async processing - simple built-in router, or bring your own by implementing a single-function interface
- works with streams
- static file/directory serving via
node-static - CORS header support
- pluggable body parsing, for non-JSON payloads
- tiny codebase (~200 LOC + optional router component)
var server = require('appy-bird');
server({
routes: [
{
// serve a static file
path: '/foo',
file: __dirname + '/foo.txt'
},
{
// serve static files from a directory
path: /^\/assets[\/$]/,
directory: __dirname + '/public'
},
{
// regex path with matches being passed to the handler
path: /^\/test-api\/(\d+)$/,
handler: function(req, matches, r) {
return r.json([req.query, matches, Math.random()]);
}
},
{
// path matching with
path: '/greet/:title/:name',
method: 'get',
handler: function(req, matches, r) {
return r.text("hello " + matches.title + " " + matches.name);
}
}
]
}).listen(8080);
cors: object specifying CORS headers. Valid keys:origin,exposeHeaders,maxAge,credentials,methods,headers. If specified, CORS headers will be injected into every response. Support forOPTIONSrequests is automatic.logger: object implementing aconsole-style interface withlog,warnanderrormethods. Defaults toconsole; passfalseto disable logging.parseQuery: function used to parse query string. Defaults to node'squerystringmodule.routes: array of routes. See Routing, below.route: instead of supplying a route array you may use this option to supply your own routing function. See Routing, below.
Routing is process of taking an HTTP request and selecting the correct handler to invoke. appy-bird provides a simple built-in router, or alternatively you can provide your own.
The built-in router represents routes as an array of objects; the first of these objects to match an incoming request "wins" and will be selected to handle it.
Valid keys to constrain those requests matched by a given route are:
path: a value that the request path must match; either a string orRegExp. String values may include colon-prefixed named segments (e.g./:controller/:action/:id), which will be collected and passed to the handler'smatchesparameter.method: string denoting required HTTP method
Route objects must also include one (and only one) of the following action keys to indicate what should happen when the route is matched:
file: absolute path of a static file to serve.directory: absolute path of a static directory to serve. The request path will be appended.handler: a handler function (see Handlers, below)
Static match, routed to handler function:
{
path: '/foobar',
handler: function(req, matches, r, res) {
// ...
}
}
Static match, routed to a static file:
{
path: '/photo.jpg',
file: __dirname + '/image.jpg'
}
Regexp match, routed to a static directory, accepting GET requests only:
{
path: /^\/assets[\/$]/,
method: 'get',
directory: __dirname + '/public'
}
Regexp match, routed to a handler function. Within the handler, matches is an array containing the regex captures:
{
path: /^\/add\/(\d+)$/,
handler: function(req, matches, response) {
// ...
}
}
Dynamic match, routed to a handler function, POST requests only. Within the handler, matches is an object with action and id keys:
{
path: '/users/:action/:id',
method: 'post',
handler: function(req, matches, r, res) {
//
}
}
To use your own your own router, simply pass a function for the route option. This function will receive a request object (see Handler parameters, below) and should return either a route descriptor, or null if no matching route was found. A route descriptor is a 2-element array of [route, matches], where route is an object containing one of the action keys described above , and matches represents any parameters that your router has extracted from the URL (or indeed from any other aspect of the request), such as Rails-style /:path/:segments. These will be passed as the second argument to the handler function.
Any route that does not resolve to a static directory or file must provide a route handler - a Javascript function to handle the request and return the reponse. Handlers have the signature:
function(request, matches, responder, response) {}Parameters:
request: the standard node HTTP request object, with some additions:request.uri: the parsed request URL (i.e.url.parse(request.url)).request.query: the parsed query string, as returned by theparseQueryserver setting.request.body: the parsed request body, if there is a registered body handler for the request's content type.
matches: any additional parameters returned by the router, typically matched URL segments, but router-dependent.responder: helper object for generating response arrays, see Responder, below.response: node HTTP response object. Use this to handle responses manually.
Handlers may return:
[status, headers, body]: standard response format.headersis an object, andbodycan be a buffer, string, or readable stream. If omitted, aContent-Lengthheader will be automatically inserted ifbodyis a string or buffer. CORS headers, if configured, will be injected automatically.boolean: return status 200 (true) or 500 (false).Promise: if handler is asynchronous, return aPromisethat resolves to any of the above.undefined: returnundefinedto indicate that the handler is taking responsibility for the request and no further response processing is required.
If a handler function throws an error, or a handler's Promise is rejected, the following will occur:
- if the error is a number, this will be used as the response status code.
- if the error has a
statusproperty, its value will be used as the response status code. - otherwise, a 500 status is used.
Errors are sent with content type text/plain.
The responder is a helper object, passed to your handler functions, that can be used to generate correctly formatted response triples.
Stream a file from the local filesystem. If mimeType is omitted it will be inferred from the filename.
Return an HTML page with optional status.
Return a JSON representation of obj with optional status.
Redirect to url.
Returns status code. If message is omitted, the textual representation of status will be used.
type, if specified, may be one of:
text(default): response body ismessagehtml: response body ismessagewrapped in an<h1>tagjson: response body is empty object
To specify type whilst retaining the default message, pass null for message.
Returns a string response with a given MIME type.
Return a plain text response with optional status.