From bb26c4bca83056ee260d9a393c09679f99052904 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Wed, 16 Apr 2014 17:30:17 -0600 Subject: [PATCH 1/3] Migrating to Express 4.0, updating tests. --- lib/application.js | 10 ++++++++++ lib/feathers.js | 8 +------- lib/providers/rest/index.js | 3 ++- package.json | 5 +++-- test/application.test.js | 29 ++++++++++++++--------------- test/providers/rest.test.js | 11 ++++------- 6 files changed, 34 insertions(+), 32 deletions(-) diff --git a/lib/application.js b/lib/application.js index 5ff5ac8a79..79ae421c01 100644 --- a/lib/application.js +++ b/lib/application.js @@ -70,6 +70,16 @@ module.exports = { return this; }, + // Express 3.x configure is gone in 4.x but we'll keep a more basic version + // That just takes a function in order to keep Feathers plugin configuration easier. + // Environment specific configurations should be done as suggested in the 4.x migration guide: + // https://github.com/visionmedia/express/wiki/Migrating-from-3.x-to-4.x + configure: function(fn){ + fn.call(this); + + return this; + }, + listen: function () { var server = this._super.apply(this, arguments); this.setup(server); diff --git a/lib/feathers.js b/lib/feathers.js index e843bd81c7..c3f4a278ec 100644 --- a/lib/feathers.js +++ b/lib/feathers.js @@ -13,16 +13,10 @@ var providers = require('./providers'); * @api public */ -function createApplication(config) { +function createApplication() { var app = express(); Proto.mixin(Application, app); app.init(); - - // Add REST provider by default, can always be disabled using app.disable('feathers 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 e814fd4fc1..6c6d6a06a4 100644 --- a/lib/providers/rest/index.js +++ b/lib/providers/rest/index.js @@ -1,5 +1,6 @@ 'use strict'; +var bodyParser = require('body-parser'); var wrappers = require('./wrappers'); module.exports = function (config) { @@ -22,7 +23,7 @@ module.exports = function (config) { app.enable('feathers rest'); - app.use(function (req, res, next) { + app.use(bodyParser()).use(function (req, res, next) { req.feathers = {}; next(); }); diff --git a/package.json b/package.json index bf1f587120..1bf15f1db8 100644 --- a/package.json +++ b/package.json @@ -35,12 +35,13 @@ }, "dependencies": { "uberproto": "~1.x", - "express": "~3.4.0", + "express": "~4.0.0", "rubberduck": "~1.x", "socket.io": "~0.9.0", "primus-emitter": "~3.x", "primus": "~2.x", - "lodash": "~2.4.1" + "lodash": "~2.4.1", + "body-parser": "~1.0.2" }, "devDependencies": { "request": "~2.x", diff --git a/test/application.test.js b/test/application.test.js index 75e817d6e4..f08a2ec63a 100644 --- a/test/application.test.js +++ b/test/application.test.js @@ -9,20 +9,15 @@ var fs = require('fs'); var feathers = require('../lib/feathers'); -describe("Express application", function() { - - it("should use express apps", function() { +describe('Feathers application', function () { + it("Express application should use express apps", function() { var app = feathers(); var child = feathers(); app.use('/path', child); - assert.equal(child.route, '/path'); + assert.equal(child.parent, app); }); - -}); - -describe('Feathers application', function () { it('registers service and looks it up with and without leading and trailing slashes', function () { var dummyService = { find: function () { @@ -64,7 +59,7 @@ describe('Feathers application', function () { }); }); - it('adds REST by default and registers SocketIO provider', function (done) { + it('adds REST and SocketIO provider', function (done) { var todoService = { get: function (name, params, callback) { callback(null, { @@ -77,9 +72,11 @@ describe('Feathers application', function () { var oldlog = console.log; console.log = function () {}; - var app = feathers().configure(feathers.socketio(function(io) { - io.set('log level', 0); - })).use('/todo', todoService); + var app = feathers() + .configure(feathers.rest()) + .configure(feathers.socketio(function(io) { + io.set('log level', 0); + })).use('/todo', todoService); var server = app.listen(6999).on('listening', function () { console.log = oldlog; @@ -116,9 +113,11 @@ describe('Feathers application', function () { var oldlog = console.log; console.log = function () {}; - var app = feathers().configure(feathers.socketio(function(io) { - io.set('log level', 0); - })).use('/secureTodos', todoService); + var app = feathers() + .configure(feathers.rest()) + .configure(feathers.socketio(function(io) { + io.set('log level', 0); + })).use('/secureTodos', todoService); var httpsServer = https.createServer({ key: fs.readFileSync(__dirname + '/resources/privatekey.pem'), diff --git a/test/providers/rest.test.js b/test/providers/rest.test.js index 2990ae0d77..d720b8a858 100644 --- a/test/providers/rest.test.js +++ b/test/providers/rest.test.js @@ -13,7 +13,7 @@ describe('REST provider', function () { var server, app; before(function () { - app = feathers().use('todo', todoService); + app = feathers().configure(feathers.rest()).use('todo', todoService); server = app.listen(4777); }); @@ -117,7 +117,7 @@ describe('REST provider', function () { } }; - var server = feathers() + var server = feathers().configure(feathers.rest()) .use(function (req, res, next) { assert.ok(req.feathers, 'Feathers object initialized'); req.feathers.test = 'Happy'; @@ -142,7 +142,7 @@ describe('REST provider', function () { }); it('throws a 405 for undefined service methods', function (done) { - var app = feathers().use('todo', { + var app = feathers().configure(feathers.rest()).use('todo', { get: function (id, params, callback) { callback(null, { description: 'You have to do ' + id }); } @@ -194,14 +194,12 @@ describe('REST provider', function () { 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 }); + var app = feathers(); 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) { @@ -213,7 +211,6 @@ describe('REST provider', function () { 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); From 059234a4a932e502a9b708d2f65e8b602ae19c65 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Wed, 16 Apr 2014 17:34:18 -0600 Subject: [PATCH 2/3] Updating documentation for REST handler setup. --- readme.md | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index 1abd497e54..17b554a113 100644 --- a/readme.md +++ b/readme.md @@ -8,12 +8,12 @@ If you are not familiar with Express head over to the [Express Guides](http://ex ### REST -Exposing services through a RESTful JSON interface is enabled by default. If you only want to use SocketIO call `app.disabled('feathers rest')` _before_ registering any services. +In almost every case you want to exposes your services through a RESTful JSON interface. This can be achieved by calling `app.configure(feathers.rest())`. To set service parameters in a middleware, just attach it to the `req.feathers` object which will become the params for any resulting service call: ```js -app.use(function(req, res) { +app.configure(feathers.rest()).use(function(req, res) { req.feathers.data = 'Hello world'; }); @@ -29,15 +29,10 @@ 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): +The default REST handler is a middleware that formats the data retrieved by the service as JSON. If you would like to configure your own `handler` middleware just pass it to `feathers.rest(handler)`. For example a middleware that 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) { +app.configure(feathers.rest(function restFormatter(req, res) { res.format({ 'text/plain': function() { res.end('The todo is: ' + res.data.description); @@ -51,8 +46,6 @@ app.use(feathers.urlencoded()).use(feathers.json()) }); ``` -__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 From e8081a31686cad35d4fd6bc8611982faa666a3f6 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Wed, 16 Apr 2014 17:39:51 -0600 Subject: [PATCH 3/3] Use Express 4 app.route() functionality for REST provider. --- lib/providers/rest/index.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/providers/rest/index.js b/lib/providers/rest/index.js index 6c6d6a06a4..bad83bf789 100644 --- a/lib/providers/rest/index.js +++ b/lib/providers/rest/index.js @@ -38,18 +38,21 @@ module.exports = function (config) { var uri = path.indexOf('/') === 0 ? path : '/' + path; - // GET / -> service.find(cb, params) - app.get(uri, app.rest.find(service)) - // GET /:id -> service.get(id, params, cb) - .get(uri + '/:id', app.rest.get(service)) + app.route(uri) + // GET / -> service.find(cb, params) + .get(app.rest.find(service)) // POST -> service.create(data, params, cb) - .post(uri, app.rest.create(service)) + .post(app.rest.create(service)); + + app.route(uri + '/:id') + // GET /:id -> service.get(id, params, cb) + .get(app.rest.get(service)) // PUT /:id -> service.update(id, data, params, cb) - .put(uri + '/:id', app.rest.update(service)) - // DELETE /:id -> service.remove(id, params, cb) - .del(uri + '/:id', app.rest.remove(service)) + .put(app.rest.update(service)) // PATCH /:id -> service.patch(id, data, params, callback) - .patch(uri + '/:id', app.rest.patch(service)); + .patch(app.rest.patch(service)) + // DELETE /:id -> service.remove(id, params, cb) + .delete(app.rest.remove(service)); app.use(uri, handler); });