I am trying to custom handle response sent to caller due to RAML specification failure. At the moment my code does the following.
const cfg = require("./cfg");
const log = require('./logging');
const RAML = require('osprey');
const startMessage = "My Service started on port " + cfg.SERVER_PORT + " at " + cfg.API_MOUNT_POINT;
// start an express server
const start = x => {
// server dependencies
const fs = require('fs'),
express = require('express'),
app = express(),
router = express.Router(),
bodyParser = require('body-parser'),
api = require('./api');
RAML.loadFile(cfg.API_SPEC).then(_raml => {
app.use(bodyParser.json({ extended: true }));
// hide the useless "powered by express" header
app.disable('x-powered-by');
// RAML validation
app.use(cfg.API_MOUNT_POINT, _raml);
app.use(cfg.API_MOUNT_POINT, api);
})
.then(v => {
app.listen(cfg.SERVER_PORT, function() {
log.info(startMessage);
});
})
.catch(e => log.error(e));
}
This works well but the response sent to caller when validation fails is shown below.
{
"errors": [
{
"type": "json",
"dataPath": "redeemtype",
"keyword": "required",
"schema": true,
"message": "Missing required property: redeemtype"
}
],
"stack": "BadRequestError: Request failed to validate against RAML definition\n at createValidationError (/Volumes/Devel/dollardine/node_modules/osprey-method-handler/osprey-method-handler.js:735:14)\n at ospreyJsonBody (/Volumes/Devel/dollardine/node_modules/osprey-method-handler/osprey-method-handler.js:448:21)\n at handle (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:56:16)\n at dispatch (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:39:20)\n at next (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:37:24)\n at jsonParser (/Volumes/Devel/dollardine/node_modules/body-parser/lib/types/json.js:94:7)\n at handle (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:56:16)\n at dispatch (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:39:20)\n at middleware (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:41:16)\n at /Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:10:16\n at ospreyContentType (/Volumes/Devel/dollardine/node_modules/osprey-method-handler/osprey-method-handler.js:325:17)\n at handle (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:56:16)\n at dispatch (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:39:20)\n at next (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:37:24)\n at ospreyMethodHeader (/Volumes/Devel/dollardine/node_modules/osprey-method-handler/osprey-method-handler.js:262:12)\n at handle (/Volumes/Devel/dollardine/node_modules/compose-middleware/lib/index.js:56:16)"
}
This is great, but I do not want to send all this info to caller. I want just log it locally and just sent {"code": 400, "message": "Invalid input"}
How can I make osprey to give me ability to handle the error response?
I found answer to my own question. In case anyone in future gets stuck here.
const start = x => {
// server dependencies
const fs = require('fs'),
express = require('express'),
app = express(),
router = express.Router(),
bodyParser = require('body-parser'),
api = require('./api');
const ramlConfig = {
"server": {
"notFoundHandler": false
},
"disableErrorInterception": true
}
osprey.loadFile(cfg.API_SPEC, ramlConfig).then(_raml => {
app.use(bodyParser.json({ extended: true }));
// hide the useless "powered by express" header
app.disable('x-powered-by');
// RAML validation
app.use(cfg.API_MOUNT_POINT, _raml);
app.use(customNotFoundHandler);
app.use(ramlErrorChecker);
app.use(cfg.API_MOUNT_POINT, api);
//app.use(ramlErrorChecker);
})
.then(v => {
app.listen(cfg.SERVER_PORT, function() {
log.info(startMessage);
});
})
.catch(e => log.error(e));
}
const ramlErrorChecker = (err, req, res, next) => {
if (err) {
log.error("RAML validation failed. Reason: " + err);
res.status(400);
return res.json(buildResponseJSON(400));
}
return next();
}
const customNotFoundHandler = (req, res, next) => {
// Check for existence of the method handler.
if (req.resourcePath) {
return next()
}
res.status(404);
return res.json({"message": "The path is not found"});
}
The important part is ramlConfig which helps in putting some customisation. By setting "disableErrorInterception" to true, we are taking over the error handling which is much better for standardisation and most importantly hiding the fact the RAML is being used. Setting "notFoundHandler" to false means, the undeclared routes are reject gracefully instead of random html.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With