Skip to content
This repository

Middleware + Nesting + Formats working together #45

Closed
wants to merge 2 commits into from

6 participants

Hunter Loftis TJ Holowaychuk Elliot Foster Tim Oxley Luc Castera Martín Ciparelli
Hunter Loftis

Removed:

tests & implementation for mapped response formats, eg:

exports.show = { json: ..., xml: ... };

Added:

tests & implementation for middleware, eg:

exports.show = [
  middleware,
  function(req, res){
    res.send('show forum ' + req.params.forum);
  }
];

tests & implementation for middleware + formats + nesting, eg:

function middleware(req, res, next) {
  req.role = 'thread owner';
  next();
}

exports.show = [
  middleware,
  function(req, res){
    if (req.format === 'json') {
      res.send(JSON.stringify({
        thread: req.params.thread,
        forum: req.params.forum,
        user: req.user,           // Should not be populated because middleware should only run for the final route
        role: req.role
      }));
    }
    else {
      res.send('show thread ' + req.params.thread + ' of forum ' + req.params.forum + ' for ' + req.user + ', ' + req.role);
    }
  }
];

assert.response(app,
      { url: '/forums/1/threads/50.json' },
      { body: '{"thread":"50","forum":"1","role":"thread owner"}'
        , headers: { 'Content-Type': 'application/json' } });
TJ Holowaychuk
Owner

+1 from me, if anyone is uses the format callbacks let us know :D

we also need a nice way to apply middleware to all of them so it's not just as verbose as app.VERB

Elliot Foster

I would prefer to see #44 merged in, leaving the per-format callback, but I'd rather have middleware than format-style callbacks.

Martín Ciparelli

+1, and +1 to have some of a middleware option to pass a middleware to all the routes on the resource.

Hunter Loftis hunterloftis closed this February 24, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 2 unique commits by 1 author.

Jan 02, 2012
Added tests and implementation for middleware using the existing Expr…
…ess Array of Functions API.
d4b0c9c
Jan 03, 2012
Tests and implementation for middleware + formats + nesting together. 0f2abab
This page is out of date. Refresh to see the latest.
24  index.js
@@ -140,22 +140,18 @@ Resource.prototype.map = function(method, path, fn){
140 140
     , fn: fn
141 141
   };
142 142
 
143  
-  // apply the route
144  
-  this.app[method](route, function(req, res, next){
  143
+  function extract_format(req, res, next) {
145 144
     req.format = req.params.format || req.format || self.format;
146 145
     if (req.format) res.contentType(req.format);
147  
-    if ('object' == typeof fn) {
148  
-      if (req.format && fn[req.format]) {
149  
-        fn[req.format](req, res, next);
150  
-      } else if (fn.default) {
151  
-        fn.default(req, res, next);
152  
-      } else {
153  
-        res.send(406);
154  
-      }
155  
-    } else {
156  
-      fn(req, res, next);
157  
-    }
158  
-  });
  146
+    next();
  147
+  }
  148
+
  149
+  // ensure fn is an array of functions and inject req.format
  150
+  if (!(fn instanceof Array)) fn = [fn];
  151
+  fn.unshift(extract_format);
  152
+  
  153
+  // apply the route
  154
+  this.app[method](route, fn);
159 155
 
160 156
   return this;
161 157
 };
26  test/fixtures/cat.js
@@ -5,4 +5,28 @@ exports.index = function(req, res){
5 5
 
6 6
 exports.new = function(req, res){
7 7
   res.send('new cat');
8  
-};
  8
+};
  9
+
  10
+exports.filter = function(req, res, next) {
  11
+  req.usertype = 'cat owner';
  12
+  next();
  13
+};
  14
+
  15
+exports.edit = [
  16
+  exports.filter,
  17
+  function(req, res) {
  18
+    res.send('usertype: ' + req.usertype);
  19
+  }
  20
+];
  21
+
  22
+exports.show = [
  23
+  exports.filter,
  24
+  function(req, res) {
  25
+    if ('json' === req.format) {
  26
+      res.send(JSON.stringify({usertype: req.usertype}));
  27
+    }
  28
+    else {
  29
+      res.send('usertype: ' + req.usertype);
  30
+    }
  31
+  }
  32
+];
43  test/fixtures/forum.middleware.js
... ...
@@ -0,0 +1,43 @@
  1
+
  2
+
  3
+function middleware(req, res, next) {
  4
+  req.user = 'middleware user';
  5
+  next();
  6
+}
  7
+
  8
+exports.index = function(req, res){
  9
+  res.send('forum index');
  10
+};
  11
+
  12
+exports.new = function(req, res){
  13
+  res.send('new forum');
  14
+};
  15
+
  16
+exports.create = function(req, res){
  17
+  res.send('create forum');
  18
+};
  19
+
  20
+exports.show = [
  21
+  middleware,
  22
+  function(req, res){
  23
+    res.send('show forum ' + req.params.forum);
  24
+  }
  25
+];
  26
+
  27
+exports.edit = function(req, res){
  28
+  res.send('edit forum ' + req.params.forum);
  29
+};
  30
+
  31
+exports.update = function(req, res){
  32
+  res.send('update forum ' + req.params.forum);
  33
+};
  34
+
  35
+exports.destroy = function(req, res){
  36
+  res.send('destroy forum ' + req.params.forum);
  37
+};
  38
+
  39
+exports.load = function(id, fn){
  40
+  process.nextTick(function(){
  41
+    fn(null, { title: 'Ferrets' });
  42
+  });
  43
+};
53  test/fixtures/thread.middleware.js
... ...
@@ -0,0 +1,53 @@
  1
+
  2
+
  3
+function middleware(req, res, next) {
  4
+  req.role = 'thread owner';
  5
+  next();
  6
+}
  7
+
  8
+exports.index = function(req, res){
  9
+  res.send('thread index of forum ' + req.params.forum);
  10
+};
  11
+
  12
+exports.new = function(req, res){
  13
+  res.send('new thread');
  14
+};
  15
+
  16
+exports.create = function(req, res){
  17
+  res.send('create thread');
  18
+};
  19
+
  20
+exports.show = [
  21
+  middleware,
  22
+  function(req, res){
  23
+    if (req.format === 'json') {
  24
+      res.send(JSON.stringify({
  25
+        thread: req.params.thread,
  26
+        forum: req.params.forum,
  27
+        user: req.user,           // Should not be populated because middleware should only run for the final route
  28
+        role: req.role
  29
+      }));
  30
+    }
  31
+    else {
  32
+      res.send('show thread ' + req.params.thread + ' of forum ' + req.params.forum + ' for ' + req.user + ', ' + req.role);
  33
+    }
  34
+  }
  35
+];
  36
+
  37
+exports.edit = function(req, res){
  38
+  res.send('edit thread ' + req.params.thread + ' of forum ' + req.params.forum);
  39
+};
  40
+
  41
+exports.update = function(req, res){
  42
+  res.send('update thread ' + req.params.thread + ' of forum ' + req.params.forum);
  43
+};
  44
+
  45
+exports.destroy = function(req, res){
  46
+  res.send('destroy thread ' + req.params.thread + ' of forum ' + req.params.forum);
  47
+};
  48
+
  49
+exports.load = function(id, fn){
  50
+  process.nextTick(function(){
  51
+    fn(null, { title: 'Tobi rules' });
  52
+  });
  53
+};
109  test/resource.content-negotiation.test.js
@@ -48,101 +48,7 @@ module.exports = {
48 48
       { url: '/pets/0.json', method: 'DELETE' },
49 49
       { body: '{"message":"pet removed"}' });
50 50
   },
51  
-  
52  
-  'test content-negotiation via format method': function(){
53  
-    var app = express.createServer();
54  
-  
55  
-    app.resource('pets', require('./fixtures/pets.format-methods'));
56  
-  
57  
-    assert.response(app,
58  
-      { url: '/pets.xml' },
59  
-      { body: '<pets><pet>tobi</pet><pet>jane</pet><pet>loki</pet></pets>'
60  
-      , headers: { 'Content-Type': 'application/xml' }});
61  
-  
62  
-    assert.response(app,
63  
-      { url: '/pets.json' },
64  
-      { body: '["tobi","jane","loki"]'
65  
-      , headers: { 'Content-Type': 'application/json; charset=utf-8' }});
66  
-  
67  
-    assert.response(app,
68  
-      { url: '/pets' },
69  
-      { body: 'Unsupported format', status: 406 });
70  
-  },
71  
-  
72  
-  'test content-negotiation via format method without default': function(){
73  
-    var app = express.createServer();
74  
-  
75  
-    app.resource('pets', require('./fixtures/pets.format-methods-without-default'));
76  
-  
77  
-    assert.response(app,
78  
-      { url: '/pets.xml' },
79  
-      { body: '<pets><pet>tobi</pet><pet>jane</pet><pet>loki</pet></pets>'
80  
-      , headers: { 'Content-Type': 'application/xml' }});
81  
-  
82  
-    assert.response(app,
83  
-      { url: '/pets.json' },
84  
-      { body: '["tobi","jane","loki"]'
85  
-      , headers: { 'Content-Type': 'application/json; charset=utf-8' }});
86  
-  
87  
-    assert.response(app,
88  
-      { url: '/pets' },
89  
-      { body: 'Not Acceptable', status: 406 });
90  
-  },
91  
-  
92  
-  'test content-negotiation via map()': function(){
93  
-    var app = express.createServer();
94  
-  
95  
-    app.use(express.bodyParser());
96  
-  
97  
-    var pets = app.resource('pets')
98  
-      , toys = app.resource('toys')
99  
-      , toysDB = ["balls", "platforms", "tunnels"];
100  
-
101  
-    toys.get('/types', function(req, res){
102  
-      res.send(toysDB);
103  
-    });  
104  
-
105  
-    toys.get('/', {
106  
-      json: function(req, res){
107  
-        res.send(toysDB);
108  
-      }
109  
-    });
110  
-    
111  
-    toys.get({
112  
-      json: function(req, res){
113  
-        res.send('"' + toysDB[req.params.toy] + '"');
114  
-      }
115  
-    });
116  
-  
117  
-    pets.add(toys);
118  
-  
119  
-    pets.get('/', {
120  
-      json: function(req, res){
121  
-        res.send({ name: 'tobi' });
122  
-      }
123  
-    });
124  
-  
125  
-    assert.response(app,
126  
-      { url: '/pets/0/toys/types' },
127  
-      { body: '["balls","platforms","tunnels"]' });
128  
-
129  
-    assert.response(app,
130  
-      { url: '/pets/0/toys/2.json' },
131  
-      { body: '"tunnels"' });
132  
-
133  
-    assert.response(app,
134  
-      { url: '/pets/0/toys.json' },
135  
-      { body: '["balls","platforms","tunnels"]' });
136 51
       
137  
-    assert.response(app,
138  
-      { url: '/pets.json' },
139  
-      { body: '{"name":"tobi"}' });
140  
-      
141  
-    assert.response(app,
142  
-      { url: '/pets' },
143  
-      { status: 406 });
144  
-  },
145  
-  
146 52
   'test nested content-negotiation': function(){
147 53
     var app = express.createServer()
148 54
       , pets = ['tobi', 'jane', 'loki'];
@@ -154,5 +60,20 @@ module.exports = {
154 60
     assert.response(app,
155 61
       { url: '/users/1/pets.json' },
156 62
       { body: '["tobi","jane","loki"]' });
  63
+  },
  64
+
  65
+  'test content-negotiation with middleware': function() {
  66
+    var app = express.createServer();
  67
+
  68
+    var cat = app.resource('api/cat', require('./fixtures/cat'));
  69
+
  70
+    assert.response(app,
  71
+      { url: '/api/cat/1' },
  72
+      { body: 'usertype: cat owner' });
  73
+
  74
+    assert.response(app,
  75
+      { url: '/api/cat/1.json' },
  76
+      { body: '{"usertype":"cat owner"}'
  77
+        , headers: { 'Content-Type': 'application/json' } });
157 78
   }
158 79
 };
34  test/resource.test.js
@@ -328,5 +328,39 @@ module.exports = {
328 328
     assert.response(app,
329 329
       { url: '/api/cat/new' },
330 330
       { body: 'new cat' });
  331
+  },
  332
+
  333
+  'test middleware by array': function() {
  334
+    var app = express.createServer();
  335
+    var cat = app.resource('api/cat', require('./fixtures/cat'));
  336
+
  337
+    assert.response(app,
  338
+      { url: '/api/cat/1/edit' },
  339
+      { body: 'usertype: cat owner' });
  340
+  },
  341
+
  342
+  'test middleware by array with shallow nesting and format': function(){
  343
+    var app = express.createServer();
  344
+
  345
+    var forum = app.resource('forums', require('./fixtures/forum.middleware'));
  346
+    var thread = app.resource('threads', require('./fixtures/thread.middleware'));
  347
+    forum.map(thread);
  348
+
  349
+    assert.response(app,
  350
+      { url: '/forums' },
  351
+      { body: 'forum index' });
  352
+
  353
+    assert.response(app,
  354
+      { url: '/forums/12' },
  355
+      { body: 'show forum 12' });
  356
+
  357
+    assert.response(app,
  358
+      { url: '/forums/12/threads' },
  359
+      { body: 'thread index of forum 12' });
  360
+    
  361
+    assert.response(app,
  362
+      { url: '/forums/1/threads/50.json' },
  363
+      { body: '{"thread":"50","forum":"1","role":"thread owner"}'
  364
+        , headers: { 'Content-Type': 'application/json' } });
331 365
   }
332 366
 };
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.