swagger-express-middleware icon indicating copy to clipboard operation
swagger-express-middleware copied to clipboard

How does one use JSON with swagger-express-middleware?

Open alex-dow opened this issue 8 years ago • 5 comments

I am struggling to get this tool to work using JSON. I feel perhaps I am not doing it correctly.

swagger-express-middleware version: 1.0.0-alpha.12

The error I always get is:

WARNING! Unable to find a Swagger path that matches "/admin/aliases"
  swagger:middleware Client requested path "/admin/aliases", which is not defined in the Swagger API. Returning HTTP 404 (Not Found) +0ms
Error: Resource not found: /admin/aliases
    at ono (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/ono/lib/index.js:62:17)
    at http404 (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/swagger-express-middleware/lib/request-validator.js:97:11)
    at Layer.handle [as handle_request] (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/express/lib/router/index.js:312:13)
    at /home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/express/lib/router/index.js:280:7
    at Function.process_params (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/express/lib/router/index.js:330:12)
    at next (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/express/lib/router/index.js:271:10)
    at http401 (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/swagger-express-middleware/lib/request-validator.js:84:3)
    at Layer.handle [as handle_request] (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/express/lib/router/index.js:312:13)

But using swagger-parser seems to work fine:

{ swagger: '2.0',
  info: 
   { description: 'foobar',
     version: '1.0.0',
     title: 'foobar',
     termsOfService: '',
     contact: 
      { name: 'Foo',
        url: 'http://www.foobar.com',
        email: '[email protected]' },
     license: { name: 'Foobar', url: 'http://www.foobar.com/foobar.html' } },
  basePath: '/',
  tags: [ { name: 'Aliases' } ],
  paths: { '/admin/aliases': { get: [Object] } },
  definitions: { aliases: { type: 'object', properties: [Object] } } }

This is my little swagger app:

process.env.DEBUG = 'swagger:middleware';

var express = require('express');
var middleware = require('swagger-express-middleware');
var path = require('path');
var app = express();

var fs = require('fs');

var swaggerJson = 'integration-tests/fixtures/swagger2.json';

middleware(swaggerJson, app, function(err, middleware) {
    if (err) {
        console.log('ERROR');
        console.log(err);
        return;
    }   

    app.use(
        middleware.metadata(),
        middleware.files(),
        middleware.parseRequest(),
        middleware.validateRequest(),
        middleware.mock()
    );  

    app.listen(8001, function() {
        console.log('Swagger service running');
    }); 
});

And my super basic swagger json file:

{
  "swagger" : "2.0",
  "info" : {
    "description" : "foobar",
    "version" : "1.0.0",
    "title" : "foobar",
    "termsOfService" : "", 
    "contact" : { 
      "name" : "Foo",
      "url" : "http://www.foobar.com",
      "email" : "[email protected]"
    },  
    "license" : { 
      "name" : "Foobar",
      "url" : "http://www.foobar.com/foobar.html"
    }   
  },  
  "basePath" : "/",
  "tags" : [ { 
    "name" : "Aliases"
  }], 
  "paths" : { 
    "/admin/aliases" : { 
      "get" : { 
        "tags" : [ "Aliases" ],
        "summary" : "Retrieve aliases.",
        "description" : "", 
        "operationId" : "getConfig",
        "consumes" : [ "application/xml", "application/json" ],
        "produces" : [ "application/xml", "application/json" ],
        "responses" : { 
          "200" : { 
            "description" : "Normal response",
            "schema" : { 
              "$ref" : "#/definitions/aliases"
            }   
          }   
        }   
      }   
    }   
  },
  "definitions" : { 
    "aliases": {
        "type": "object",
        "properties": {
            "value": {
                "type": "string",
                "description": "some string",
                "default": "foobar"
            }
        }
    }
  }
}

I'm not sure why it thinks /admin/aliases is an invalid path and I suspect I'm loading the json file incorrectly.

alex-dow avatar May 05 '16 15:05 alex-dow

Interesting, when visiting http://localhost:8000//admin/aliases (notice the double slash) the behavior is different:

  swagger:middleware GET //admin/aliases matches Swagger path /admin/aliases +0ms
  swagger:middleware Validating Accept header (application/json) +4ms
  swagger:middleware Validating Content-Length header (NaN) +2ms
  swagger:middleware Using 200 response for GET //admin/aliases +0ms
  swagger:middleware Running the queryResource mock +1ms
  swagger:middleware ERROR! 404 - GET //admin/aliases does not exist +2ms
Error: //admin/aliases Not Found
    at ono (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/ono/lib/index.js:62:17)
    at /home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/swagger-express-middleware/lib/mock/query-resource.js:34:15
    at doCallback (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/swagger-express-middleware/lib/data-store/index.js:303:5)
    at /home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/swagger-express-middleware/lib/data-store/index.js:49:7
    at Immediate.<anonymous> (/home/adowgail/workspace.otif-admin-uis/otif-app-api-admin-ui/node_modules/swagger-express-middleware/lib/data-store/index.js:290:5)
    at Immediate.immediate._onImmediate (timers.js:440:18)
    at processImmediate [as _immediateCallback] (timers.js:383:17)

this seems to suggest that I need to explicitly mock the results of the path, but the first sample doesn't seem to require this.

I should also point out that I am making my test requests with the appropriate content-type and accept headers set to application/json

alex-dow avatar May 05 '16 16:05 alex-dow

Removing basePath from the swagger.json also brings me to the second log output.

alex-dow avatar May 05 '16 16:05 alex-dow

speaking with some folks in the office who know more about swagger than I do, I'm beginning to think my problem (other than the basepath issue) is that the swagger.json file contains no example values and instead just contains the schema. I will have to try delivering a fake value to see if that works.

alex-dow avatar May 05 '16 16:05 alex-dow

so ultimately our swagger files do not have default values for all the APIs which pretty much negates the benefits of this tool sadly (was hoping to avoid boilerplate code!). I was able to get it working using the memory data store, but the whole point of trying out this tool was to avoid boilerplate. Maybe I can convince the java folks to put some example values in their annotations? :(

But along the way of evaluating it I guess there are two bugs:

if basePath is /, then /endpoint won't match but //endpoint will.

if an endpoint exists, but has no value to return, the error is a confusing 404. It's confusing because a 404 implies that the endpoint doesn't exist, not that it has no content to return.

Ideally it should return a 500 as this is a server error that a client can't recover from (or maybe a 204 if the swagger definitions allow for it? not sure)

alex-dow avatar May 05 '16 18:05 alex-dow

Actually, I stand corrected. The tool's memory storage means it is still relevant to my needs, I just need to fill in that data ;) But still feel that those issues I mentioned are still bugs for which I'll open separate issues.

alex-dow avatar May 06 '16 14:05 alex-dow