Comparing version 0.18.0 to 0.19.0
@@ -54,2 +54,24 @@ <h1 align="center">Fastify</h1> | ||
<a name="extend-server-error"></a> | ||
**extendServerError** | ||
If you need to extend the standard [server error](https://github.com/fastify/fastify/blob/master/docs/Reply.md#errors), this api is what you need. | ||
You *must* pass a function that returns an object, Fastify will extend the server error with the returned object of your function. | ||
```js | ||
fastify.extendServerError(() => { | ||
return { | ||
timestamp: new Date() | ||
} | ||
}) | ||
/* | ||
The resulting object will be: | ||
{ | ||
error: String | ||
message: String | ||
statusCode: Number | ||
timestamp: Date | ||
} | ||
*/ | ||
``` | ||
<a name="sync-async"></a> | ||
@@ -56,0 +78,0 @@ #### Sync and Async |
@@ -23,2 +23,11 @@ <h1 align="center">Fastify</h1> | ||
If you want to pass a custom error code to the user, just pass it as second parameter to `next()`: | ||
```js | ||
fastify.addHook('onRequest', (req, res, next) => { | ||
// some code | ||
next(new Error('some error'), 400) | ||
}) | ||
``` | ||
*The error will be handled by [`Reply`](https://github.com/fastify/fastify/blob/master/docs/Reply.md#errors).* | ||
The function signature is always the same, `request`, `response`, `next`, it changes a little bit only in the `'preHandler'` hook, where the first two arguments are [`request`](https://github.com/fastify/fastify/blob/master/docs/Request.md) and [`reply`](https://github.com/fastify/fastify/blob/master/docs/Reply.md) core Fastify objects. | ||
@@ -25,0 +34,0 @@ |
@@ -25,10 +25,14 @@ <h1 align="center">Fastify</h1> | ||
If you need to run a middleware only under certains path(s), just pass the path as first parameter to `use` and you are done! | ||
*Note that this does not support routes with parameters, (eg: `/user/:id/comments`)* | ||
*Note that this does not support routes with parameters, (eg: `/user/:id/comments`) and wildcard is not supported in multiple paths.* | ||
```js | ||
// Single path | ||
fastify.use('/public', staticFiles('/assets')) | ||
middie.use('/public', staticFiles('/assets')) | ||
// Wildcard path | ||
middie.use('/public/*', staticFiles('/assets')) | ||
// Multiple paths | ||
fastify.use(['/public', '/dist'], staticFiles('/assets')) | ||
middie.use(['/public', '/dist'], staticFiles('/assets')) | ||
``` |
@@ -92,6 +92,16 @@ <h1 align="center">Fastify</h1> | ||
#### Errors | ||
If you pass to *send* an object that is an instance of *Error*, Fastify will automatically set the error code to 500 if is not setted or if the *statusCode* is lower than 500. | ||
If you pass to *send* an object that is an instance of *Error*, Fastify will automatically create an error structured as the following: | ||
```js | ||
{ | ||
error: String // the http error message | ||
message: String // the user error message | ||
statusCode: Number // the http status code | ||
} | ||
``` | ||
If you want it extend this error, check out [`extendServerError`](https://github.com/fastify/fastify/blob/master/docs/Decorators.md#extend-server-error). | ||
*If you are passing an error to send and the statusCode is less than 400, Fastify will automatically set it at 500.* | ||
<a name="payload-type"></a> | ||
#### Type of the final payload | ||
It is crucial that the sent payload is a `string` or a `Buffer`, otherwise *send* will throw at runtime. |
@@ -94,2 +94,3 @@ 'use strict' | ||
fastify.decorateRequest = decorator.decorateRequest | ||
fastify.extendServerError = decorator.extendServerError | ||
@@ -149,5 +150,6 @@ fastify._Reply = Reply | ||
function middlewareCallback (err) { | ||
function middlewareCallback (err, code) { | ||
if (err) { | ||
const reply = new Reply(this.req, this.res, null) | ||
if (code[0]) reply.code(code[0]) | ||
reply.send(err) | ||
@@ -159,5 +161,6 @@ return | ||
function routeCallback (err) { | ||
function routeCallback (err, code) { | ||
if (err) { | ||
const reply = new Reply(this.req, this.res, null) | ||
if (code[0]) reply.code(code[0]) | ||
reply.send(err) | ||
@@ -164,0 +167,0 @@ return |
@@ -49,2 +49,15 @@ 'use strict' | ||
function extendServerError (fn) { | ||
if (typeof fn !== 'function') { | ||
throw new TypeError('The server error object must be a function') | ||
} | ||
if (typeof fn() !== 'object' || fn() === null || Array.isArray(fn())) { | ||
throw new TypeError('The error extender must return an object') | ||
} | ||
this._Reply.prototype['_extendServerError'] = fn | ||
return this | ||
} | ||
function decorateRequest (name, fn, dependencies) { | ||
@@ -68,3 +81,4 @@ if (checkExistence(this._Request, name)) { | ||
decorateReply: decorateReply, | ||
decorateRequest: decorateRequest | ||
decorateRequest: decorateRequest, | ||
extendServerError: extendServerError | ||
} |
@@ -6,2 +6,3 @@ /* eslint-disable no-useless-return */ | ||
const runHooks = require('fastseries')() | ||
const Reply = require('./reply') | ||
const validation = require('./validation') | ||
@@ -27,2 +28,5 @@ const validateSchema = validation.validate | ||
} | ||
setImmediate(wrapReplyEnd, req, res, 415) | ||
return | ||
} | ||
@@ -39,3 +43,4 @@ | ||
} | ||
setImmediate(wrapResEnd, res, '', 415) | ||
setImmediate(wrapReplyEnd, req, res, 415) | ||
return | ||
@@ -46,3 +51,3 @@ } | ||
setImmediate(wrapResEnd, res, '', 415) | ||
setImmediate(wrapReplyEnd, req, res, 405) | ||
return | ||
@@ -76,3 +81,3 @@ } | ||
if (err) { | ||
setImmediate(wrapResEnd, res, '', 422) | ||
setImmediate(wrapReplyEnd, req, res, 422) | ||
return | ||
@@ -86,3 +91,3 @@ } | ||
if (valid !== true) { | ||
setImmediate(wrapResEnd, res, valid, 400) | ||
setImmediate(wrapReplyEnd, req, res, 400, valid) | ||
return | ||
@@ -111,4 +116,5 @@ } | ||
function preHandlerCallback (err) { | ||
function preHandlerCallback (err, code) { | ||
if (err) { | ||
if (code[0]) this.reply.code(code[0]) | ||
this.reply.send(err) | ||
@@ -123,5 +129,5 @@ return | ||
function wrapResEnd (res, payload, statusCode) { | ||
res.statusCode = statusCode | ||
res.end(payload) | ||
function wrapReplyEnd (req, res, statusCode, payload) { | ||
const reply = new Reply(req, res, null) | ||
reply.code(statusCode).send(new Error(payload || '')) | ||
return | ||
@@ -128,0 +134,0 @@ } |
@@ -7,4 +7,7 @@ /* eslint-disable no-useless-return */ | ||
const safeStringify = require('fast-safe-stringify') | ||
const xtend = require('xtend') | ||
const validation = require('./validation') | ||
const serialize = validation.serialize | ||
const statusCodes = require('./status-codes.json') | ||
const stringify = JSON.stringify | ||
@@ -17,2 +20,3 @@ function Reply (req, res, handle) { | ||
this._serializer = null | ||
// this._extendServerError = () => {} | ||
} | ||
@@ -41,4 +45,15 @@ | ||
if (payload && payload.isBoom) { | ||
this._req.log.error(payload) | ||
this.res.statusCode = payload.output.statusCode | ||
setImmediate( | ||
wrapReplyEnd, | ||
this, | ||
safeStringify(payload) | ||
) | ||
return | ||
} | ||
if (payload instanceof Error) { | ||
if (!this.res.statusCode || this.res.statusCode < 500) { | ||
if (!this.res.statusCode || this.res.statusCode < 400) { | ||
this.res.statusCode = 500 | ||
@@ -48,3 +63,11 @@ } | ||
this._req.log.error(payload) | ||
setImmediate(wrapReplyEnd, this, safeStringify(payload)) | ||
setImmediate( | ||
wrapReplyEnd, | ||
this, | ||
stringify(xtend({ | ||
error: statusCodes[this.res.statusCode + ''], | ||
message: payload.message, | ||
statusCode: this.res.statusCode | ||
}, this._extendServerError && this._extendServerError())) | ||
) | ||
return | ||
@@ -51,0 +74,0 @@ } |
{ | ||
"name": "fastify", | ||
"version": "0.18.0", | ||
"version": "0.19.0", | ||
"description": "Fast and low overhead web framework, for Node.js", | ||
@@ -37,2 +37,3 @@ "main": "fastify.js", | ||
"bluebird": "^3.5.0", | ||
"boom": "^4.3.1", | ||
"cors": "^2.8.3", | ||
@@ -69,7 +70,8 @@ "coveralls": "^2.13.1", | ||
"find-my-way": "^0.2.2", | ||
"middie": "^0.2.0", | ||
"middie": "^0.3.0", | ||
"pino-http": "^2.6.1", | ||
"pump": "^1.0.2", | ||
"shot": "^3.4.0" | ||
"shot": "^3.4.0", | ||
"xtend": "^4.0.1" | ||
} | ||
} |
@@ -130,8 +130,12 @@ 'use strict' | ||
t.strictEqual(response.statusCode, 400) | ||
t.deepEqual(JSON.parse(body)[0], { | ||
keyword: 'type', | ||
dataPath: '.test', | ||
schemaPath: '#/properties/test/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
t.deepEqual(JSON.parse(body), { | ||
error: 'Bad Request', | ||
message: JSON.stringify([{ | ||
keyword: 'type', | ||
dataPath: '.test', | ||
schemaPath: '#/properties/test/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
}]), | ||
statusCode: 400 | ||
}) | ||
@@ -162,8 +166,12 @@ }) | ||
t.strictEqual(response.statusCode, 400) | ||
t.deepEqual(JSON.parse(body)[0], { | ||
keyword: 'type', | ||
dataPath: '.hello', | ||
schemaPath: '#/properties/hello/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
t.deepEqual(JSON.parse(body), { | ||
error: 'Bad Request', | ||
message: JSON.stringify([{ | ||
keyword: 'type', | ||
dataPath: '.hello', | ||
schemaPath: '#/properties/hello/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
}]), | ||
statusCode: 400 | ||
}) | ||
@@ -170,0 +178,0 @@ }) |
@@ -179,8 +179,12 @@ 'use strict' | ||
t.strictEqual(response.statusCode, 400) | ||
t.deepEqual(JSON.parse(body)[0], { | ||
keyword: 'type', | ||
dataPath: '.test', | ||
schemaPath: '#/properties/test/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
t.deepEqual(JSON.parse(body), { | ||
error: 'Bad Request', | ||
message: JSON.stringify([{ | ||
keyword: 'type', | ||
dataPath: '.test', | ||
schemaPath: '#/properties/test/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
}]), | ||
statusCode: 400 | ||
}) | ||
@@ -211,8 +215,12 @@ }) | ||
t.strictEqual(response.statusCode, 400) | ||
t.deepEqual(JSON.parse(body)[0], { | ||
keyword: 'type', | ||
dataPath: '.hello', | ||
schemaPath: '#/properties/hello/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
t.deepEqual(JSON.parse(body), { | ||
error: 'Bad Request', | ||
message: JSON.stringify([{ | ||
keyword: 'type', | ||
dataPath: '.hello', | ||
schemaPath: '#/properties/hello/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
}]), | ||
statusCode: 400 | ||
}) | ||
@@ -219,0 +227,0 @@ }) |
@@ -80,8 +80,12 @@ 'use strict' | ||
t.strictEqual(response.statusCode, 400) | ||
t.deepEqual(body[0], { | ||
keyword: 'type', | ||
dataPath: '.hello', | ||
schemaPath: '#/properties/hello/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
t.deepEqual(body, { | ||
error: 'Bad Request', | ||
message: JSON.stringify([{ | ||
keyword: 'type', | ||
dataPath: '.hello', | ||
schemaPath: '#/properties/hello/type', | ||
params: { type: 'integer' }, | ||
message: 'should be integer' | ||
}]), | ||
statusCode: 400 | ||
}) | ||
@@ -88,0 +92,0 @@ }) |
@@ -6,4 +6,2 @@ /* eslint-disable no-useless-return */ | ||
const test = t.test | ||
const request = require('request') | ||
const http = require('http') | ||
const internals = require('../../lib/handleRequest')[Symbol.for('internals')] | ||
@@ -48,3 +46,3 @@ const Request = require('../../lib/request') | ||
buildSchema(handle) | ||
internals.handler(handle, null, null, res, { hello: 'world' }, null) | ||
internals.handler(handle, null, { log: { error: () => {} } }, res, { hello: 'world' }, null) | ||
}) | ||
@@ -87,26 +85,1 @@ | ||
}) | ||
test('json body shoudl return 422 if the body is not correctly parsed', t => { | ||
t.plan(3) | ||
const server = http.createServer((req, res) => { | ||
internals.jsonBody(req, res) | ||
}) | ||
server.listen(0, err => { | ||
t.error(err) | ||
server.unref() | ||
request({ | ||
method: 'POST', | ||
uri: 'http://localhost:' + server.address().port, | ||
headers: { | ||
'Content-Type': 'application/json' | ||
}, | ||
body: '{"hello":world"}' | ||
}, (error, response, body) => { | ||
t.error(error) | ||
t.strictEqual(response.statusCode, 422) | ||
}) | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
173596
80
4707
6
11
25
+ Addedxtend@^4.0.1
+ Addedmiddie@0.3.0(transitive)
- Removedmiddie@0.2.0(transitive)
Updatedmiddie@^0.3.0