Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
generic ReST client and server : nodejs implementation of spore (Specification to a POrtable Rest Environment)
JavaScript
tag: 0.1.5

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
examples
lib
tests
.gitmodules
.npmignore
LICENSE
Makefile
README.md
package.json

README.md

Spore on Node

node-spore is an implementation of Spore in Node.

It provide a generic ReST client and server.

Install

npm install spore

Client

spore.createClient(spore_spec)

You can contruct a client with object:

var spore = require('spore');
spore.createClient({
                "base_url" : "http://api.twitter.com/1",
                "version" : "0.1",
                "methods" : {
                ....
                }
});

With a json string:

spore.createClient('{"base_url": ...}');

With a file:

var client = spore.createClient(__dirname +'/twitter.json');

With an url (asynchronous):

spore.createClientWithUrl('http://example.net/spore.json', function(err, client) {
    // do something with client
});

You can create a client with a spec splitted in multiple files:

var client = spore.createClient(__dirname +'/twitter1.json',
                                __dirname +'/twitter2.json');

To override/modify a spec:

var client = spore.createClient(__dirname +'/twitter.json',
                                {base_url: 'http://identi.ca/'});

Usage

client.method_name([middleware, ][params, ][payload, ]callback)

  • params: hash with key/value (optional)
  • payload: content of the request (optional)
  • callback: function with 2 parameters, err (a string) and result (see Response object)

If a required parameter is not defined, callback is immediatly called with err !== null.

Method with payload:

client.method_name(params, payload, callback)

Example:

client.method_name({id: 42}, 'payload', function(err, result) {
    ...
});

Method without params:

client.method_name(callback)
client.method_name(payload, callback)

Misc.

If you just want to perform a GET request, use client.get(url, callback):

client.get('http://example.com/me', function(err, result) {

});

Get the specification as object with client.spec:

console.log(client.spec.base_url);

Middlewares

Middleware in spore-node are inspired by connect.

With middleware you can handle authentication, special body serialization or some special case. Because in real life, most API sucks.

Middleware is a function. Middleware should call next, with null (and next middleware will be called), a response (no more middleware will be called and request is abort), a callback (will be called after response received), or an error.

var middleware = function(method, request, next) {
    if (method.authentication) {
        request.headers['accept'] = 'text/html';
    }
    next(function(response, next) {
        response.status = 500;
        next();
    });
};
spore.createClient(middleware, __dirname +'/twitter.json');

You can many middlewares:

spore.createClient(middleware1, middleware2, __dirname +'/twitter.json');

If a middleware throw an exception, then the callback is immediatly called, and err param contain exception.

You can also enable middleware with client::enable:

var client = spore.createClient(__dirname +'/twitter.json');
client.enable(middleware);

Or enable enable middleware only if:

var client = spore.createClient(__dirname +'/twitter.json');
client.enable_if(function(method, request) {
    if (!method.authentication) {
        return false;
    }
    return true;
}, middleware);

Or disable a middleware:

client.disable(middleware);

You can have a middleware per method:

client.method_name(middleware, [params, ][payload, ]callback)

Method object

Method represent the current method in spore description file.

If API required authentication for all methods and a method specify ''authentication'' to false, method.authentication is false.

Same for formats and expected_status.

Request object

  • port: server port (80, 443, ...)
  • host: host (example.com)
  • scheme: scheme or the url (http, https)
  • method: http method (GET, POST, ...)
  • path_info: request uri with placeholder (/1/example/:id)
  • uri: readonly request uri without placehoder (/1/example/42)
  • query_string: query string as key/value (empty, except path have a query string)
  • headers: http request headers as keys/values({'User-Agent': 'node-spore', 'Cookie': '...'})
  • params: request params as keys/values ({id: 42})
  • payload: payload

Response object

  • status: status code (200, ...)
  • headers: response headers as keys/values
  • body

Modify request

Adding http headers:

function(method, request, next) {
    request.headers['Content-Length'] = 42;
    next();
}

Modify params:

function(method, request, next) {
    request.params.id = 'myid';
    next();
}

Return response:

function(method, request, next) {
    next({
       status   : 200,
       headers : {},
       body    : ''
    });
}

Modify response

Adding http headers:

function(method, request, next) {
    next(function(response, next) {
        response.headers['Content-type'] = 'text/html';
        next();
    });
}

Transform body:

function(method, request, next) {
    next(function(response, next) {
        response.data = JSON.parse(response.data);
        next();
    });
}

Interrupt response middlewares by return response:

function(method, request, callback) {
    next(function(response, next) {
        response.headers['Content-type'] = 'text/html';
        next(response);
    });
}

AuthBasic middleware

HTTP Basic auth for all requests.

var AuthBasic = require('spore').middlewares.basic(username, password);

OAuth1 middleware

Sign each requests with authentication == true. Require node-oauth.

var OAuth = require('oauth');
var oauth = new OAuth(requestUrl, accessUrl, consumerKey, consumerSecret, version, null, "HMAC-SHA1");
var OAuthMiddleware = require('spore').middlewares.oauth1(oauth, access_token, access_token_secret);

OAuth2 middleware

Sign each requests with authentication == true.

var oauth2 = require('spore').middlewares.oauth2(access_token);

Status middleware

Check if response code match expected_status in spec. Throw exception if status is not expected.

var StatusMiddleware = require('spore').middlewares.status()`

FormatJson middleware

Parse JSON response if content-type is application/json.

var JsonMiddleware = require('spore').middlewares.json()`

Runtime middleware

Add X-Spore-Runtime to the response headers. The value of the header is the time the request took to be executed.

var RuntimeMiddleware = require('spore').middlewares.runtime()`

Server

Connect middleware:

var spore = require('spore');
var middleware = spore.middleware(__dirname +'/twitter.json', {
    public_timeline: function(req, res) {
        res.send('Hello word !');
    }
});
var app = require('connect').createServer(middleware);
app.listen(3000);

Tests

$> git submodule update --init
$> make test

Examples

See examples/.

Spore spec compatibility

API

  • base_url: OK
  • authentication: OK (via middleware)
  • expected_status: OK (via middleware)

Methods

  • method: OK
  • path: OK
  • optional_params: OK
  • required_params: OK
  • expected_status: OK (via middleware)
  • authentication: OK (via middleware)
  • base_url: OK
  • required_payload: OK
  • deprecated: OK
  • headers: OK
  • unattended_params: OK
  • form-data: NOK

Compatibility

0.1.x run on node >= 0.4.0.

0.0.3 run on node 0.2.x.

Links

License

BSD

Changelog

  • 0.1.5

    Add middleware per method.

    Remove node-base64 dependency for auth basic middleware.

    Always set content-length header for methods POST, PUT, DELETE.

  • 0.1.4

    Fix: GET and HEAD methods can have a payload.

  • 0.1.3

    Set content-length header when a payload is provided.

  • 0.1.2

    Add client.get(url, callback).

    Fix requests and missing 'var'.

  • 0.1.1

    Fix npm publish.

    No more include tests/* in npm package.

    You should use require('spore').middlewares for using build-in middlewares.

  • 0.1.0

    Initial server support with connect. Feedback is welcome.

    Construct client with an url.

    Middlewares can now call next with an error.

    Some internal refactoring.

    Now work on node 0.4. Support of node 0.2.x have been dropped.

  • 0.0.3

    Normalize HTTP verb to upper case.

    Handle headers with placeholder.

    Warning when you are using a deprecated method.

    Handle unattended_params.

    Added request.query_string.

    Added AuthBasic and OAuth2 middlewares.

    Fixed https support.

    Runtime, status and json middlewares are function. incompatible change

  • 0.0.2

    Middlewares are no more object but a function. incompatible change

    Middlewares are also async. The third or second argument is a callback next. incompatible change

    Response middlewares can return a response object and break the chain.

    Added some middlewares (json, status, runtime and oauth1).

    Added enable, enable_if and disable methods.

    Create client with multiple spec file.

    Added uri to request object.

    Handle http error.

  • 0.0.1

    Initial version.

Something went wrong with that request. Please try again.