From eda0e251d593ac3b7e1928d1b2021034fe76a56f Mon Sep 17 00:00:00 2001 From: David Luecke Date: Tue, 8 Apr 2014 08:51:21 -0600 Subject: [PATCH] Allow to configure REST handler manually (#40) --- lib/feathers.js | 8 +++-- lib/providers/rest/index.js | 13 +++++--- readme.md | 26 +++++++++++++++ test/providers/rest.test.js | 64 +++++++++++++++++++++++++++++++++---- 4 files changed, 98 insertions(+), 13 deletions(-) diff --git a/lib/feathers.js b/lib/feathers.js index a95f94a064..e843bd81c7 100644 --- a/lib/feathers.js +++ b/lib/feathers.js @@ -13,12 +13,16 @@ var providers = require('./providers'); * @api public */ -function createApplication() { +function createApplication(config) { var app = express(); Proto.mixin(Application, app); app.init(); + // Add REST provider by default, can always be disabled using app.disable('feathers rest') - app.use(express.urlencoded()).use(express.json()).configure(providers.rest()); + if(!config || config.rest) { + app.use(express.urlencoded()).use(express.json()).configure(providers.rest()); + } + return app; } diff --git a/lib/providers/rest/index.js b/lib/providers/rest/index.js index 12b13b07c4..e814fd4fc1 100644 --- a/lib/providers/rest/index.js +++ b/lib/providers/rest/index.js @@ -1,19 +1,22 @@ 'use strict'; -var _ = require('lodash'); var wrappers = require('./wrappers'); module.exports = function (config) { config = config || {}; - var responder = config.responder || function (req, res) { - res.format(_.extend({ + var handler = config.handler || function (req, res) { + res.format({ 'application/json': function () { res.json(res.data); } - }, config.formatters)); + }); }; + if(typeof config === 'function') { + handler = config; + } + return function () { var app = this; @@ -47,7 +50,7 @@ module.exports = function (config) { // PATCH /:id -> service.patch(id, data, params, callback) .patch(uri + '/:id', app.rest.patch(service)); - app.use(uri, responder); + app.use(uri, handler); }); }; }; diff --git a/readme.md b/readme.md index d179701d28..33d005b605 100644 --- a/readme.md +++ b/readme.md @@ -29,6 +29,32 @@ app.use('/todos', { }); ``` +The default REST handler is a middleware that formats the data retrieved by the service as JSON. REST handling will be set up automatically when calling `var app = feathers()`. If you would like to configure the REST provider yourself, call `var app = feathers({ rest: false });`. + +Then you can configure it manually and add your own `handler` middleware that, for example just renders plain text with the todo description (`res.data` contains the data returned by the service): + +```js +var app = feathers({ rest: false }); + +app.use(feathers.urlencoded()).use(feathers.json()) + .configure(feathers.rest(function restFormatter(req, res) { + res.format({ + 'text/plain': function() { + res.end('The todo is: ' + res.data.description); + } + }); + })) + .use('/todo', { + get: function (id, params, callback) { + callback(null, { description: 'You have to do ' + id }); + } + }); +``` + +__Note:__ When configuring REST this way, you *have* to add `app.use(feathers.urlencoded()).use(feathers.json())` to support request body parsing. + +If you want to add other middleware *before* the REST handler, simply call `app.use(middleware)` before configuring the handler. + ### SocketIO To expose services via [SocketIO](http://socket.io/) call `app.configure(feathers.socketio())`. It is also possible pass a `function(io) {}` when initializing the provider where `io` is the main SocketIO object. Since Feathers is only using the SocketIO default configuration, this is a good spot to initialize the [recommended production settings](https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO#recommended-production-settings): diff --git a/test/providers/rest.test.js b/test/providers/rest.test.js index d3e9c074ce..507153b9c9 100644 --- a/test/providers/rest.test.js +++ b/test/providers/rest.test.js @@ -141,16 +141,16 @@ describe('REST provider', function () { }); }); - it('throws a 405 for undefined service methods', function(done) { + it('throws a 405 for undefined service methods', function (done) { var app = feathers().use('todo', { - get: function(id, params, callback) { - callback(null, { description: 'You have to do ' + id }); - } - }); + get: function (id, params, callback) { + callback(null, { description: 'You have to do ' + id }); + } + }); /* jshint ignore:start */ // Error handler - app.use(function(error, req, res, next) { + app.use(function (error, req, res, next) { assert.equal(error.message, 'Can not call service method .find'); res.json({ message: error.message }); }); @@ -168,4 +168,56 @@ describe('REST provider', function () { }); }); }); + + it('disables REST and lets you set the handler manually', function(done) { + var app = feathers({ rest: false }); + + app.configure(feathers.rest(function restFormatter(req, res) { + res.format({ + 'text/plain': function() { + res.end('The todo is: ' + res.data.description); + } + }); + })) + .use('/todo', { + get: function (id, params, callback) { + callback(null, { description: 'You have to do ' + id }); + } + }); + + var server = app.listen(4776); + request('http://localhost:4776/todo/dishes', function (error, response, body) { + assert.equal(body, 'The todo is: You have to do dishes'); + server.close(done); + }); + }); + + it('Lets you configure your own middleware before the handler (#40)', function(done) { + var data = { description: 'Do dishes!', id: 'dishes' }; + var app = feathers({ rest: false }); + + app.use(function defaultContentTypeMiddleware (req, res, next) { + req.headers['content-type'] = req.headers['content-type'] || 'application/json'; + next(); + }) + .use(feathers.urlencoded()) + .use(feathers.json()) + .configure(feathers.rest()) + .use('/todo', { + create: function (data, params, callback) { + callback(null, data); + } + }); + + var server = app.listen(4775); + request({ + method: 'POST', + url: 'http://localhost:4775/todo', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data) + }, function (error, response, body) { + assert.deepEqual(JSON.parse(body), data); + server.close(done); + }); + }); });