node-spore is an implementation of Spore in Node.
It provide a generic ReST client and server.
npm install spore
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/'});
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)
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);
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 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.
- 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
- status: status code (200, ...)
- headers: response headers as keys/values
- body
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 : ''
});
}
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);
});
}
HTTP Basic auth for all requests.
var AuthBasic = require('spore').middlewares.basic(username, password);
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);
Sign each requests with authentication == true.
var oauth2 = require('spore').middlewares.oauth2(access_token);
Check if response code match expected_status in spec. Throw exception if status is not expected.
var StatusMiddleware = require('spore').middlewares.status()`
Parse JSON response if content-type is application/json.
var JsonMiddleware = require('spore').middlewares.json()`
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()`
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);
$> git submodule update --init
$> make test
See examples/.
- base_url: OK
- authentication: OK (via middleware)
- expected_status: OK (via middleware)
- 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
0.1.x run on node >= 0.4.0.
0.0.3 run on node 0.2.x.
- Spore specification
- Some Spore description are already available
- node-spore and IndexTank
- node-spore and node-intervals
BSD
-
0.1.6
Updated tests to be node 0.6 compatible.
-
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.