Skip to content

Commit 9783d4e

Browse files
committed
processResponse option
1 parent 4444274 commit 9783d4e

5 files changed

Lines changed: 132 additions & 42 deletions

File tree

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,14 @@ app.listen(3000);
4949

5050
Now you can send POST requests to `/js` endpoint with the body containing the script and an optional data instance that will be processed by JSONScript interpreter. For example, with this request:
5151

52-
```json
52+
```javascript
5353
{
5454
"script": {
5555
"res1": {
56-
"$exec": "router",
57-
"$method": "get",
56+
"$exec": "router", // executor name can be changed in options
57+
"$method": "get", // $method can be get/post/put/delete
5858
"$args": { "path": "/resource/1" }
59+
// method property in $args can be used instead of $method
5960
},
6061
"res2": {
6162
"$exec": "router",
@@ -85,6 +86,15 @@ the response will be a combination of two responses (both requests are processed
8586
}
8687
```
8788

89+
If option `processResponse: "body"` were used the result would have been:
90+
91+
```javascript
92+
{
93+
"res1": { /* response body 1 */ },
94+
"res2": { /* response body 2 */ }
95+
}
96+
```
97+
8898
JSONScript also supports sequential evaluation, conditionals, data manipulation etc. So you can implement an advanced logic in your script and it will be executed in the server without sending responses of individual requests to the client.
8999

90100
See [JSONScript Language](https://github.com/JSONScript/jsonscript/blob/master/LANGUAGE.md) for more information.
@@ -116,13 +126,17 @@ Defaults:
116126
{
117127
routerExecutor: 'router',
118128
basePath: '',
129+
processResponse: undefined,
119130
jsonscript: { strict: true },
120131
Promise: undefined
121132
}
122133
```
123134

124135
- _routerExecutor_: the name of the executor (the value of "$exec" keyword in the instruction) used to access Express router, `"router"` is used by default.
125136
- _basePath_: the path used as a prefix to paths in the script $exec instruction arguments.
137+
- _processResponse_: possible values:
138+
- `"body"` - return only response body if status code is < 300, throw an exception otherwise.
139+
- function - custom function to process the response object, can throw an exception or return the object to be used as the result.
126140
- _jsonscript_: options passed to JSONScript interpreter [jsonscript-js](https://github.com/JSONScript/jsonscript-js).
127141
- _Promise_: an optional Promise class, the native Promise is used by default.
128142

index.js

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,10 @@ function jsonscriptExpress(app, options) {
1515
jsonscript: { strict: true },
1616
Promise: (typeof Promise !== 'undefined') && Promise
1717
});
18+
19+
var processResponce = processResponceFunc(options);
1820
var js = JSONScript(options.jsonscript);
19-
METHODS.forEach(function (method) {
20-
execRouter[method] = function(args) {
21-
if (args.method && args.method != method) {
22-
console.warn('method specified in args (' + args.method +
23-
') is different from $method in instruction (' + method + '), used ' + method);
24-
}
25-
args.method = method;
26-
return execRouter(args);
27-
};
28-
});
21+
addExecutorMethods();
2922
js.addExecutor(options.routerExecutor, execRouter);
3023
evaluator.js = js;
3124

@@ -41,7 +34,7 @@ function jsonscriptExpress(app, options) {
4134
.then(function (value) {
4235
res.send(value);
4336
}, function (err) {
44-
res.status(err.errors ? 400 : 500)
37+
res.status(err.errors ? 400 : err.statusCode || 500)
4538
.send({
4639
error: err.message,
4740
errors: err.errors
@@ -67,10 +60,53 @@ function jsonscriptExpress(app, options) {
6760
return new options.Promise(function (resolve, reject) {
6861
request.end(function (err, resp) {
6962
if (err) return reject(err);
70-
resp = _.pick(resp, 'statusCode', 'headers', 'body');
71-
resp.request = args;
72-
resolve(resp);
63+
resolve(processResponce(resp, args));
7364
});
7465
});
7566
}
67+
68+
69+
function addExecutorMethods() {
70+
METHODS.forEach(function (method) {
71+
execRouter[method] = function(args) {
72+
if (args.method && args.method != method) {
73+
console.warn('method specified in args (' + args.method +
74+
') is different from $method in instruction (' + method + '), used ' + method);
75+
}
76+
args.method = method;
77+
return execRouter(args);
78+
};
79+
});
80+
}
7681
}
82+
83+
84+
function processResponceFunc(options) {
85+
return options.processResponse == 'body'
86+
? bodyProcessResponce
87+
: typeof options.processResponse == 'function'
88+
? options.processResponse
89+
: defaultProcessResponse;
90+
}
91+
92+
93+
function bodyProcessResponce(resp) {
94+
if (resp.statusCode < 300) return resp.body;
95+
throw new HttpError(resp);
96+
}
97+
98+
99+
function defaultProcessResponse(resp, args) {
100+
resp = _.pick(resp, 'statusCode', 'headers', 'body');
101+
resp.request = args;
102+
return resp;
103+
}
104+
105+
106+
function HttpError(resp) {
107+
this.message = resp.body ? JSON.stringify(resp.body) : 'Error';
108+
this.statusCode = resp.statusCode;
109+
}
110+
111+
HttpError.prototype = Object.create(Error.prototype);
112+
HttpError.prototype.constructor = HttpError;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jsonscript-express",
3-
"version": "0.1.1",
3+
"version": "0.2.0",
44
"description": "Express middleware for batch processing using JSONScript",
55
"main": "index.js",
66
"scripts": {

spec/app.js

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
'use strict';
22

33
var express = require('express');
4-
var app = express();
54
var bodyParser = require('body-parser');
65
var jsonscript = require('..');
6+
var _ = require('lodash');
77

88

9-
app.use(bodyParser.json());
9+
module.exports = function createApp(jsonscriptOptions) {
10+
var app = express();
1011

11-
app.get('/api/:name/:id', function (req, res) {
12-
var id = req.params.id;
13-
send(res, req.params.name, id);
14-
});
12+
app.use(bodyParser.json());
1513

16-
app.post('/api/:name', function (req, res) {
17-
var id = Date.now();
18-
send(res, req.params.name, id, req.body);
19-
});
20-
21-
app.post('/js', jsonscript(app, { basePath: '/api' }));
22-
23-
function send(res, name, id, data) {
24-
res.send({
25-
name: name,
26-
id: id,
27-
info: 'resource ' + name + ' id ' + id,
28-
data: data
14+
app.get('/api/:name/:id', function (req, res) {
15+
var id = req.params.id;
16+
send(res, req.params.name, id);
2917
});
30-
}
3118

19+
app.post('/api/:name', function (req, res) {
20+
var id = Date.now();
21+
send(res, req.params.name, id, req.body);
22+
});
3223

33-
if (!module.parent) app.listen(3000);
34-
35-
module.exports = app;
24+
jsonscriptOptions = jsonscriptOptions
25+
? _.extend({ basePath: '/api' }, jsonscriptOptions)
26+
: { basePath: '/api' };
27+
app.post('/js', jsonscript(app, jsonscriptOptions));
28+
29+
function send(res, name, id, data) {
30+
res.send({
31+
name: name,
32+
id: id,
33+
info: 'resource ' + name + ' id ' + id,
34+
data: data
35+
});
36+
}
37+
38+
return app;
39+
};

spec/handler.spec.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
'use strict';
22

33
var test = require('supertest');
4-
var app = require('./app');
4+
var createApp = require('./app');
55
var assert = require('assert');
66

77

88
describe('jsonscript handler', function() {
9+
var app;
10+
11+
beforeEach(function() {
12+
app = createApp();
13+
});
14+
15+
916
describe('single instruction without $method', function() {
1017
it('should process GET', function (done) {
1118
test(app)
@@ -177,6 +184,35 @@ describe('jsonscript handler', function() {
177184
});
178185
});
179186
});
187+
188+
189+
describe('options', function() {
190+
describe('processResponse: "body"', function() {
191+
beforeEach(function() {
192+
app = createApp({ processResponse: 'body' });
193+
});
194+
195+
it('should return response body only', function (done) {
196+
test(app)
197+
.post('/js')
198+
.set('Accept', 'application/json')
199+
.send({
200+
script: {
201+
$exec: 'router',
202+
$args: {
203+
method: 'get',
204+
path: '/object/1'
205+
}
206+
}
207+
})
208+
.expect(200)
209+
.end(function (err, resp) {
210+
assert.deepEqual(resp.body, { name: 'object', id: 1, info: 'resource object id 1' });
211+
done();
212+
});
213+
});
214+
});
215+
});
180216
});
181217

182218

0 commit comments

Comments
 (0)