Socket
Socket
Sign inDemoInstall

appy-bird

Package Overview
Dependencies
10
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.1 to 1.0.0

test/end-to-end.js

43

index.js

@@ -14,4 +14,8 @@ const fs = require('fs');

const CORS_HEADERS = {
origin : 'Access-Control-Allow-Origin',
headers : 'Access-Control-Allow-Headers'
origin : 'Access-Control-Allow-Origin',
exposeHeaders : 'Access-Control-Expose-Headers',
maxAge : 'Access-Control-Max-Age',
credentials : 'Access-Control-Allow-Credentials',
methods : 'Access-Control-Allow-Methods',
headers : 'Access-Control-Allow-Headers',
};

@@ -69,13 +73,10 @@

},
status: function(code, message, html) {
if (message === true || message === false) {
html = message;
message = null;
status: function(status, message, type) {
message = status + ' ' + (message || httpStatus[status]);
switch (type || 'text') {
case 'html': return responder.html(status, '<h1>' + message + '</h1>');
case 'json': return responder.json(status, {});
case 'text': return responder.text(status, message);
default: throw new Error("unknown response type: " + type);
}
message = code + ' ' + (message || httpStatus[code]);
if (html) {
return responder.html(code, '<h1>' + message + '</h1>');
} else {
return responder.text(code, message);
}
},

@@ -147,3 +148,7 @@ string: function(status, mimeType, str) {

} else {
_handleResponse(route.handler(req, matches, responder, res));
try {
_handleResponse(route.handler(req, matches, responder, res));
} catch (e) {
_handleError(e);
}
}

@@ -162,6 +167,3 @@ }

return _handleResponse(res);
}, function(err) {
if (typeof err === 'number') err = { status: err };
return _handleResponse(responder.status(err.status || 500));
});
}, _handleError);
} else {

@@ -172,2 +174,7 @@ return _sendResponse(response[0], response[1], response[2]);

function _handleError(e) {
if (typeof e === 'number') e = { status: e };
_handleResponse(responder.status(e.status || 500));
}
function _sendResponse(status, headers, body) {

@@ -179,4 +186,2 @@ if (!('Content-Length' in headers)) {

headers['Content-Length'] = body.byteLength();
} else {
return _handleResponse(responder.status(500));
}

@@ -183,0 +188,0 @@ }

{
"name": "appy-bird",
"version": "0.0.1",
"version": "1.0.0",
"description": "'appy-bird makes APIs as easy as flying into a brick wall!",

@@ -5,0 +5,0 @@ "main": "index.js",

# appy-bird
`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.
## Features
* `rack`-style request handling; action handlers simply return `[status, headers, body]` triples...
* ...or return a `Promise` if 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)
## Quick Start
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);
## API
### Options
### Options
* `cors`: object specifying CORS headers. Valid keys: `origin`, `exposeHeaders`, `maxAge`, `credentials`, `methods`, `headers`. If specified, CORS headers will be injected into every response. Support for `OPTIONS` requests is automatic.
* `parseQuery`: function used to parse query string. Defaults to node's `querystring` module.
* `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
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.
#### Using the built-in router
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 or `RegExp`. String values may include colon-prefixed named segments (e.g. `/:controller/:action/:id`), which will be collected and passed to the handler's `matches` parameter.
* `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)
##### Examples
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) {
//
}
}
#### Using your own router
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.
### Handlers
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:
```javascript
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 the `parseQuery` server 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. `headers` is an object, and `body` can be a buffer, string, or readable stream. If omitted, a `Content-Length` header will be automatically inserted if `body` is 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 a `Promise` that resolves to any of the above.
* `undefined`: return `undefined` to indicate that the handler is taking responsibility for the request and no further response processing is required.
#### Error Handling
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 `status` property, its value will be used as the response status code.
* otherwise, a 500 status is used.
Errors are sent with content type `text/plain`.
### Responder
The responder is a helper object, passed to your handler functions, that can be used to generate correctly formatted response triples.
#### `responder.html([status], html)`
Return an HTML page with optional `status`.
#### `responder.json([status], obj)`
Return a JSON representation of `obj` with optional `status`.
#### `responder.status(status, [message], [type])`
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 is `message`
* `html`: response body is `message` wrapped in an `&lt;h1&gt;` tag
* `json`: response body is empty object
To specify `type` whilst retaining the default `message`, pass `null` for `message`.
#### `responder.string(status, mimeType, str)`
Returns a string response with a given MIME type.
#### `responder.text([status], text)`
Return a plain text response with optional `status`.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc