Warning This is an experimental project.
PBX is a reimagining of Patchboard with the following design goals:
Support for the Patchboard API description schema
Modularization of the architecture
Simplification of request classification
Support for ES6 (mostly via generator/promise-based interfaces)
Optimizations for common development scenarios
Although PBX is currently a single library, the idea is to package and release it as several standalone libraries that can interoperate. We want to empower developers to pick and choose the tools they want to use and to ultimately be able to create their our Patchboard-based solutions.
These components include:
A validator that uses JSCK for JSON schema validation. Validators are used to validate API definitions, query parameters, and request and response bodies.
A client that uses Shred to generate HTTP API clients based on the API definition.
A builder for creating API definitions quickly, much like you can do with frameworks like Restify and Express (except the definitions are valid Patchboard API definitions and can be discovered/reflected upon).
A classifier for determining the
(resource, action)pair associated with a given request.
A context object that provides a series of helper methods for dealing with requests and responses, leveraging the API definition to do so.
A processor that provides a standard request handler for use with the Node HTTP API.
A collection of behaviors encapsulating common API scenarios, such as providing an HTTP interface to a storage backend.
Example: A Simple Blog Engine
First, let's define our API:
require "pbx"builderdefine "blogs"path: "/blogs"postas: "create"creates: "blog"builderdefine "blog"template: "/blogs/:name"getput authorization: truedelete authorization: truepostcreates: "post"authorization: trueschemarequired: "name""title"properties:name: type: "string"title: type: "string"builderdefine "post"template: "/blog/:name/:key"getput authorization: truedelete authorization: trueschemarequired: "key""title""content"properties:key: type: "string"title: type: "string"content: type: "string"builderreflectmodule.exports = builderapi
This API allows to create blogs, view and update them, and delete them. We can also do the same for posts within a blog. Requests that update our blog require authorization. We also added reflection to our API, which means the Patchboard API definition is available via a
GET request to
For example, if we have a blog named
my-blog and a post named
pbx-example, the API above would allow us to read that post with the following
$ curl 'http://acmeblogging.com/blog/my-blog/pbx-example' -H'accept:application.vnd.post+json;version=1.0
Let's serve up the API using the Node HTTP
require "when/generator"require "pbx"api = require "./api"call ->require "http"createServer yield processor api->listen 8080
If we run this, we'll have an HTTP server for our API running on port
localhost. We can even use
curl to get a description of the interface:
$ curl http://localhost:8080/ -H'accept: application/json'
Wait, though…this API doesn't actually do anything. We haven't created any behaviors to bind it to. That's what's going on with the function we're passing into the
pbx function, which returns an empty object literal:
pbx function takes our API definition and an initializer function that returns a set of handlers for each action defined by the API.
These dynamic implementation patterns are called behaviors. Behaviors open up a variety of possibilities for implementations. In this example, we'll simply define explicit handler functions for each action. But behaviors make it possible to encapsulate an reuse common patters (like storing a resource in a database).
See the example app for more.