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

patchboard

v0.5.4

Published

Patchboard API server and tools

Downloads

48

Readme

Patchboard

Patchboard streamlines the development of REST API services by using a serializable API definition that is easy to write and easy to read. With it, you can eliminate the repetition and brittleness involved in writing and maintaining an API provided a server and used by clients in multiple languages.

Given a description of your URLs, resources, and schemas, Patchboard provides a Node.js server that validates HTTP requests and dispatches them to resource handlers you define. The server exposes the API Definition as JSON, which a Patchboard client can use to self-assemble the logic needed to interact with the API.

Because the API Definition is serializable, Patchboard clients that consume it at runtime can be implemented in any sufficiently dynamic language. At this time, only a JavaScript client has been written.

API Definition format

Examples are excerpts from the Trivial example, which is written in CoffeeScript.

Mappings

A dictionary that maps arbitrary logical names to resources and the URLs used to access them.


module.exports =

  users:
    resource: "users"
    path: "/users"

  user_search:
    resource: "user"
    path: "/user"
    query:
      login:
        required: true
        type: "string"

  user:
    resource: "user"
    template: "/users/:id"

Schemas

A JSON Schema (currently limited to draft 3) describing the data structures used by an API. Resource schemas are defined as properties of the top level definitions field.


media_type = (name) ->
  "application/vnd.trivial.#{name}+json;version=1.0"

module.exports =

  id: "urn:patchboard.trivial"
  definitions:

    resource:
      extends: {$ref: "urn:patchboard#resource"}

    user:
      extends: {$ref: "#resource"}
      mediaType: media_type "user"
      properties:
        login:
          required: true
          type: "string"
          pattern: "^[a-zA-z0-9_.]{3,32}"
        email:
          type: "string"
          format: "email"
        password:
          type: "string"
          minLength: 4
          maxLength: 64
        questions: {$ref: "#questions"}

Resources

A dictionary describing the resources provided by the API. Each top level field defines a resource.

An excerpt of the Trivial example:


type = (name) ->
  "application/vnd.trivial.#{name}+json;version=1.0"

module.exports =
  users:
    actions:
      create:
        method: "POST"
        request:
          type: type "user"
        response:
          type: type "user"
          status: 201

  user_search:
    actions:
      get:
        method: "GET"
        response:
          type: type "user"
          status: 200

  user:
    actions:
      get:
        method: "GET"
        response:
          type: type "user"
          status: 200
      delete:
        method: "DELETE"
        response:
          status: 204

For each resource, the actions dictionary defines the available actions, specifying the HTTP method, the request and/or response media types, and the status that signifies a successful response.

Implementing a Patchboard Service

Validate your definition

Patchboard includes a JSON Schema that describes a valid API Definition. A convenient way to validate your definition is to use bin/patchboard.

bin/patchboard validate path/to/api.json # or api.coffee, or api.js

You can also print a basic example definition to STDOUT.

bin/patchboard example json # or cson

Patchboard.Server

Patchboard = require "patchboard"
api = require "./api"
handlers = require "./handlers"

server = new Patchboard.Server api,
  # Host and port to listen for HTTP requests
  host: "127.0.0.1", port: 1979
  # The base URL for resources
  url: "http://localhost:1979/"
  handlers: handlers

Request Handlers

The request handler object is a dictionary of dictionaries. The top level fields correspond to resource names, with the fields in the values mapping to actions. For each resource + action, you define a function which takes a request Context object as its argument.

In the following simplified example, the module exports a function which takes an application instance as its argument, then returns the handlers dictionary.

module.exports = (application) ->

  users:
    create: (context) ->
      {match, request} = context
      content = request.body
      application.create_user content, (error, result) -> 
        if error
          context.error error.name, error.message
        else
          context.respond match.success_status, result

  user:
    get: (context) ->
      application.get_user context.match.path.id, (error, result) ->
        if error
          context.error error.name, error.message
        else
          context.respond match.success_status, result
    update: (context) ->
      {match, request} = context
      id = match.path.id
      content = request.body
      application.update_user id, content, (error, result) ->
        if error
          context.error error.name, error.message
        else
          context.respond match.success_status, result

Note that the callback passed to the application methods could easily be refactored into a function and used as the default for simple actions.

Request Context

The default Patchboard dispatcher calls handler functions with an instance of Context as an argument. Contexts bundle together the objects representing the HTTP request and response, as well as providing helper functions such as respond and error

Using a Patchboard Client

Example use of the JavaScript client (in CoffeeScript).

Client = require("patchboard").Client
# or you can require "patchboard-js" directly

# retrieve the API Definition from a Patchboard server and assemble a client.
Client.discover "http://localhost:1979/", (error, client) ->
  throw error if error
  
  client.resources.users.create {login: "matthew"}, (error, response) ->
    throw error if error

    user = response.resource
    user.update {email: "[email protected]"}, (error, response) ->