npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

pbx

v1.0.0-beta-08

Published

Modular server implementation based on Patchboard API schema

Downloads

38

Readme

PBX

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:

{Builder} = require "pbx"
builder.define "blogs",
  path: "/blogs"
.post
  as: "create"
  creates: "blog"

builder.define "blog",
  template: "/blogs/:name"
.get()
.put authorization: true
.delete  authorization: true
.post
  creates: "post"
  authorization: true
.schema
  required: ["name", "title"]
  properties:
    name: type: "string"
    title: type: "string"

builder.define "post",
  template: "/blog/:name/:key"
.get()
.put authorization: true
.delete authorization: true
.schema
  required: ["key", "title", "content"]
  properties:
    key: type: "string"
    title: type: "string"
    content: type: "string"

builder.reflect()

module.exports = builder.api

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 command:

$ 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 createServer method:

{call} = require "when/generator"
{processor} = 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 8080 on 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: (-> {}).

The pbx function takes our API definition and an initializer function that returns a set of handlers for each action defined by the API.

Separation of Interface and Implementation Defining the API interface separate from the implementation is different from most other HTTP libraries. One benefit of this separation is that we can generate our implementation based on the API, or even make it dynamic (say, using JavaScript proxies).

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.