Wednesday March 26, 2014 - tags:    node.js, express, swagger, express-validation

swagger, describing an express REST API

Swagger is a simple, open standard for describing REST APIs. Below is my take on creating a swagger client for node.js and express. The solution does not require comments and does not run as express middleware.

express-validation-swagger

express-validation-swagger generates a swagger enabled client, using express-validation to define the validation rules for an express route. We will also use swagger-ui a swagger client; which contains the client files required to support a swagger api.

npm install express-validation-swagger  
npm install express-validation  
npm install swagger-ui  

setup

in order to add swagger to your express application import express-validation-swagger and define the following options:

  1. title is the name given to th swagger web site
  2. statics is the location of the swagger-ui client files
  3. resources is the location of your generated swagger resource files
  4. applicationUrl is the url of your application, this is inserted into the swagger client (see below)
  5. routes contains an array of routes (see below)

swagger will be hosted here: http://127.0.0.1:3000/swagger

var swagger = require('express-validation-swagger');

swagger(app, {  
  title : 'express validation swagger', 
  statics : '/test/public/swagger/',  
  resources : '/test/swagger/', 
  applicationUrl : 'http://127.0.0.1:3000',
  routes : [
    { page : 'user', method : 'GET',    path: '/user', validation : validation.user.get },
    { page : 'user', method : 'POST',   path: '/user', validation : validation.user.post },
    { page : 'user', method : 'DELETE', path: '/user', validation : validation.user.del },
    { page : 'user', method : 'PUT',    path: '/user', validation : validation.user.put }
  ]
});

swagger-ui template changes

In order to specify where to host swagger amend the swagger-ui index.html file, the url element should equal {{applicationUrl}}.

$(function () {
  window.swaggerUi = new SwaggerUi({
  url: "{{applicationUrl}}",
  dom_id: "swagger-ui-container",
  supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
  onComplete: function(swaggerApi, swaggerUi){
    if(console) {
      console.log("Loaded SwaggerUI")
    }
    $('pre code').each(function(i, e) {hljs.highlightBlock(e)});
  },
  onFailure: function(data) {
    if(console) {
      console.log("Unable to Load SwaggerUI");
      console.log(data);
    }
  },
  docExpansion: "none"
});

configuring express-validation rules

Simply define a collection of rules; like so; more info here: express-validation

var validation = {  
  user : { 
    get : { 
      headers: { userid : Joi.string().required().regex(/^[0-9a-fA-F]{24}$/) }
    },
    post : { 
      headers: { userid : Joi.string().required().regex(/^[0-9a-fA-F]{24}$/) }
      , body: { username : Joi.string().required() }
    },
    del : { 
      headers: { userid : Joi.string().required().regex(/^[0-9a-fA-F]{24}$/) }
    },
    put : { 
      headers: { userid : Joi.string().required().regex(/^[0-9a-fA-F]{24}$/) }
    }
  }
};

example

Here is a full listing; we also include handlebars/consolidate so that we can set the applicationUrl in our test/public/swagger/index.html file. The source code for express-validation-swagger contains a working example.

Simply run:

npm install  
node test/app.js  
var express = require('express')  
  , cons = require('consolidate')
  , http = require('http')
  , swagger = require('../lib/swagger/main')
  , validate = require('express-validation')
  , Joi = require('joi')
  , app = express();

app.engine('html', cons.handlebars);  
app.set('view engine', 'html');  
app.set('views', 'public');

var validation = {  
  user : { 
    get : { 
      headers: { userid : Joi.string().required().regex(/^[0-9a-fA-F]{24}$/) }
    },
    post : { 
      headers: { userid : Joi.string().required().regex(/^[0-9a-fA-F]{24}$/) }
      , body: { username : Joi.string().required() }
    },
    del : { 
      headers: { userid : Joi.string().required().regex(/^[0-9a-fA-F]{24}$/) }
    },
    put : { 
      headers: { userid : Joi.string().required().regex(/^[0-9a-fA-F]{24}$/) }
    }
  }
};

var services = {  
  user : {
    get : function (req, res, next) {
      var user = { "userId" : "530d1d22be018c1121025be1", "name" : "airasoul" };
      res.json(200, user);
    },
    post : function (req, res, next) {
      var user = { "userId" : "530d1d22be018c1121025be1", "name" : "airasoul" };
      res.json(201, user);
    },
    del : function (req, res, next) {
      var user = { "userId" : "530d1d22be018c1121025be1", "name" : "airasoul" };
      res.json(204, user);
    },
    put : function (req, res, next) {
      var user = { "userId" : "530d1d22be018c1121025be1", "name" : "airasoul" };
      res.json(204, user);
    }
  }
}

app.get('/user', validate(validation.user.get),  services.user.get);  
app.post('/user', validate(validation.user.post),  services.user.post );  
app.del('/user', validate(validation.user.del),   services.user.del);  
app.put('/user', validate(validation.user.put),   services.user.put);

swagger(app, {  
  title : 'express validation swagger', 
  statics : '/test/public/swagger/',  
  resources : '/test/swagger/', 
  applicationUrl : 'http://127.0.0.1:3000',
  routes : [
    { page : 'user', method : 'GET',    path: '/user', validation : validation.user.get },
    { page : 'user', method : 'POST',   path: '/user', validation : validation.user.post },
    { page : 'user', method : 'DELETE', path: '/user', validation : validation.user.del },
    { page : 'user', method : 'PUT',    path: '/user', validation : validation.user.put }
  ]
});

app.use(app.router);  
http.createServer(app).listen(3000);  
module.exports = app;

run tests

Start the express application:

npm install  
node test/app.js  

Now run the tests:

grunt test