Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

swagger tools error handler middleware not catching errors

overview

My custom errorHandler middleware is not catching the swagger-tools request validator error. Instead, the swagger tools HTML error is sent back to the client. How can I get my errorHandler middleware to catch the swagger tools validation error and respond to the client accordingly?

my prognosis

I'm rather clueless unfortunately. No matter where I put the app.use(errorHandler) directive, the swagger tools html error is returned to the client and my errorHandler function never catches the error.

Maybe I'm overlooking something overtly incorrect about my setup. Below is my app.js file and below my app.js is the [undesired] swagger-tools HTML error response that is returned to the client. Again, I have tried putting the app.use(errorHandler) literally (figuratively) everywhere, despite the fact that the below code only shows it in two places.

app.js

"use strict";

var swaggerTools = require("swagger-tools");
var compression = require("compression");
var app = require("express")();
var logger = require("./config/logger");
var projectConfig = require("./config/projectConfig");
var debug = require("debug")("app-js"); // run this to enable debug logging DEBUG=app-js node app.js

// swaggerRouter configuration
var options = {
    controllers: './api/controllers',
    useStubs: false
};

// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
var swaggerDoc = require('./api/swagger/swagger.json');

// compress all requests except those which have Cache-Control header with the no-transform directive
app.use(compression());

// for testing
module.exports = app;

// global error handler
function errorHandler(err, req, res, next, statusCode) {
    logger.error(err);
    debug(err);
    if (res.headersSent) {
        return next(err);
    } else {
        res.status(statusCode || 500).json(projectConfig.genericErrorResponse(statusCode || 500, err.message || err || "something blew up and the err object was undefined"));
    }
}

// handles timed out requests
function haltOnTimedout(req, res, next) {
    if (!req.timedout) {
        next();
    } else {
        debug("\nrequest timed out!\n");
        next("the request timed out", null, null, null, 504);
    }
}

// Initialize the Swagger middleware
swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {
    "use strict"

    // Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
    app.use(middleware.swaggerMetadata());

    app.use(function (req, res, next) {
        res.header("Access-Control-Allow-Origin", "*"); // CORS should be parametrized by configuration
        res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        next();
    });

    // Validate Swagger requests
    // app.use(middleware.swaggerValidator());

    app.use(middleware.swaggerValidator({
        validateResponse: false
    }));

    app.use(haltOnTimedout);
    app.use(errorHandler);

    // Route validated requests to appropriate controller
    app.use(middleware.swaggerRouter(options));
});

app.use(haltOnTimedout);
app.use(errorHandler);

app.listen(projectConfig.port || process.env.PORT || 9000)
    .on("connection", function (socket) {
        debug("\na new cxn was made by a client.\n");
        socket.setTimeout(projectConfig.expressTimeout || 120000);
    })

swagger tools html error returned to client

Error: Parameter (copy) failed schema validation
<br> &nbsp; &nbsp;at throwErrorWithCode (/Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/swagger-tools/lib/validators.js:121:13)
<br> &nbsp; &nbsp;at Object.module.exports.validateAgainstSchema (/Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/swagger-tools/lib/validators.js:176:7)
<br> &nbsp; &nbsp;at /Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/swagger-tools/middleware/swagger-validator.js:143:22
<br> &nbsp; &nbsp;at /Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/async/lib/async.js:356:13
<br> &nbsp; &nbsp;at async.forEachOf.async.eachOf (/Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/async/lib/async.js:233:13)
<br> &nbsp; &nbsp;at _asyncMap (/Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/async/lib/async.js:355:9)
<br> &nbsp; &nbsp;at Object.map (/Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/async/lib/async.js:337:20)
<br> &nbsp; &nbsp;at validateValue (/Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/swagger-tools/middleware/swagger-validator.js:136:11)
<br> &nbsp; &nbsp;at /Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/swagger-tools/middleware/swagger-validator.js:343:21
<br> &nbsp; &nbsp;at /Users/cuv/Documents/dev/dev-project/dev-simple/node_modules/async/lib/async.js:356:13

what versions am i running?

node:

node --version
v6.2.2

latest versions of swagger-tools and express:

"swagger-tools": "^0.10.1",
"express": "^4.12.3"

close

Any help and/or insight into how to get my errorHandler middleware to catch and thereby override the swagger-tools html error would be very much obliged. I've posted my question in the apigee community forums as well, as it is part of an apigee-127 project. https://community.apigee.com/questions/29267/swagger-tools-error-handler-middleware-not-catchin.html

Thanks!

like image 431
Chris Covney Avatar asked Jul 28 '16 21:07

Chris Covney


1 Answers

I see two problems.

At first: error handler must have 4 args, so statusCode will be ignored.

errorHandler(err, req, res, next) // correct definition

Second place is

next("the request timed out", null, null, null, 504);

First argument of error handle must be Error object not String, so correct code will be

next(new Error("the request timed out")); // other args passed by closure

There are many variants how pass statusCode.

// 1. Bad way: Pass string with delimiter
next(new Error("the request timed out;404"));
...
// In error handler
var args = err.message.split() // => args[0] = the request timed out, args[1] = 404

// 2. Check message error text
If (err.message == 'the request timed out')  
    statusCode = 404;

// 3. Best way is use custom error

More about custom error here

like image 151
Aikon Mogwai Avatar answered Oct 14 '22 13:10

Aikon Mogwai