Example #1
0
 var createRunner = function (doc, callback) {
   Runner.create({
     appRoot: '.',
     startWithErrors: true,
     swagger: doc,
     fittingsDirs: [ './fittings' ],
     defaultPipe: 'swagger_controllers',
     swaggerControllerPipe: 'swagger_controllers',
     bagpipes: {
       '_swagger_params_parser': {
         name: 'swagger_params_parser',
         jsonOptions: {
           type: ['json', 'application/*+json'],
           limit: 5 * 1024 * 1024
         }
       },
       _router: {
         name: 'swagger_router',
         mockMode: false,
         mockControllersDirs: [ 'api/mocks' ],
         controllersDirs: [ './controllers' ]
       },
       'any_controllers': [
         'cors',
         'any_handler',
         '_swagger_params_parser',
         '_router'
       ],
       'swagger_controllers': [
         'cors',
         '_swagger_params_parser',
         '_router'
       ]
     }
   }, function (err, runner) {
     if (err) {
       callback(err);
       return;
     }
     runner.expressMiddleware().register(app);
     callback();
   });
 };
Example #2
0
    initialize: function initialize(cb) {

      var config = {
        appRoot: sails.config.appPath,
        configDir: sails.config.paths.config,
        controllersDirs: [sails.config.paths.controllers],
        mockControllersDirs: [path.resolve(sails.config.paths.controllers, '..', 'mocks')],
        swaggerFile: path.resolve(sails.config.paths.controllers, '..', 'swagger', "swagger.yaml")
      };

      SwaggerRunner.create(config, function(err, runner) {
        if (err) { return cb(err); }

        var sailsMiddleware = runner.sailsMiddleware();
        chain = sailsMiddleware.chain();

        sails.hooks['swagger-sails-hook'].runner = runner;

        return cb();
      });
    },
Example #3
0
/**
 * Configure swagger node runner with the app.
 * It loads the swagger specification and maps everything with an active express app.
 *
 * @module
 * @see Parent: {@link config}
 * @requires fs
 * @requires js-yaml
 * @requires path
 * @requires swagger-node-runner
 * @param {Object} app - An express app to which map the swagger details
 * @param {Object} config - Application Configurations
 * @param {Object} logger - Application Logger
 * @param {Object} scope - Application Scope
 * @param {function} cb - Callback function
 * @returns {void}
 */
function bootstrapSwagger(app, config, logger, scope, cb) {
	// Register modules to be used in swagger fittings
	require('../helpers/swagger_module_registry').bind(scope);

	// Register the express middleware(s)

	// Restrict access based on rules
	app.use(middleware.applyAPIAccessRules.bind(null, config));

	// Bind each request/response pair to its own domain
	app.use(require('express-domain-middleware'));

	// Maximum 2mb body size for POST type requests
	app.use(bodyParser.raw({ limit: '2mb' }));

	// Maximum 2mb body size for json type requests
	app.use(bodyParser.json({ limit: '2mb' }));

	// Maximum 2mb body size for URL encoded requests
	app.use(
		bodyParser.urlencoded({
			extended: true,
			limit: '2mb',
			parameterLimit: 5000,
		})
	);

	// Allow method override for any request
	app.use(methodOverride());

	// Custom query param parsing
	app.use(middleware.queryParser());

	// Log request message
	app.use(middleware.logClientConnections.bind(null, logger));

	/**
	 * Instruct browser to deny display of <frame>, <iframe> regardless of origin.
	 *
	 * RFC -> https://tools.ietf.org/html/rfc7034
	 */
	app.use(
		middleware.attachResponseHeader.bind(null, 'X-Frame-Options', 'DENY')
	);

	/**
	 * Set Content-Security-Policy headers.
	 *
	 * frame-ancestors - Defines valid sources for <frame>, <iframe>, <object>, <embed> or <applet>.
	 *
	 * W3C Candidate Recommendation -> https://www.w3.org/TR/CSP/
	 */
	app.use(
		middleware.attachResponseHeader.bind(
			null,
			'Content-Security-Policy',
			"frame-ancestors 'none'"
		)
	);

	// Log if there is any error
	app.use(middleware.errorLogger.bind(null, logger));

	// Load Swagger controllers and bind the scope
	var controllerFolder = '/api/controllers/';
	fs.readdirSync(config.root + controllerFolder).forEach(file => {
		if (path.basename(file) !== 'index.js') {
			// eslint-disable-next-line import/no-dynamic-require
			require(config.root + controllerFolder + file)(scope);
		}
	});

	var swaggerConfig = {
		appRoot: config.root,
		configDir: `${config.root}/config/swagger`,
		swaggerFile: path.join(`${config.root}/schema/swagger.yml`),
		enforceUniqueOperationId: true,
		startWithErrors: false,
		startWithWarnings: true,
	};

	// Swagger express middleware
	SwaggerRunner.create(swaggerConfig, (errors, runner) => {
		if (errors) {
			// Ignore unused definition warning
			errors.validationWarnings = _.filter(
				errors.validationWarnings,
				error => error.code !== 'UNUSED_DEFINITION'
			);

			// Some error occurred in configuring the swagger
			if (!_.isEmpty(errors.validationErrors)) {
				logger.error('Swagger Validation Errors:');
				logger.error(errors.validationErrors);
			}

			if (!_.isEmpty(errors.validationWarnings)) {
				logger.error('Swagger Validation Warnings:');
				logger.error(errors.validationWarnings);
			}

			if (
				!_.isEmpty(errors.validationErrors) ||
				!_.isEmpty(errors.validationWarnings)
			) {
				cb(errors);
				return;
			}
		}

		// Swagger express middleware
		var swaggerExpress = runner.expressMiddleware();

		// Check the response and act appropriately on error
		runner.on('responseValidationError', validationResponse => {
			// TODO: Troubleshoot why default validation hook considers json response as string response
			if (validationResponse.errors[0].code !== 'INVALID_RESPONSE_BODY') {
				logger.error('Swagger Response Validation Errors:');
				logger.error(validationResponse.errors[0].errors);
			}
		});

		// Install middleware
		swaggerExpress.register(app);

		// To be used in test cases or getting configuration runtime
		app.swaggerRunner = runner;

		// Managing all the queries which were not caught by previous middlewares.
		app.use((req, res, next) => {
			// We need to check if the response is already handled by some other middlewares/fittings/controllers
			// In case not, we consider it as 404 and send default response
			// res.headersSent is a patch, and only works if above middlewares set some header no matter the status code
			// Another possible workaround would be res.bodySize === 0
			if (!res.headersSent) {
				res.status(404);
				res.json({ description: 'Page not found' });
			}
			next();
		});

		swaggerHelper
			.getResolvedSwaggerSpec()
			.then(resolvedSchema => {
				// Successfully mounted the swagger runner
				cb(null, {
					swaggerRunner: runner,
					definitions: resolvedSchema.definitions,
				});
			})
			.catch(reason => {
				cb(reason);
			});
	});
}
Example #4
0
'use strict';

var SwaggerRunner = require('swagger-node-runner');
var Hapi = require('hapi');
var app = new Hapi.Server();

module.exports = app; // for testing

var config = {
  appRoot: __dirname // required config
};

SwaggerRunner.create(config, function(err, runner) {
  if (err) { throw err; }

  var port = process.env.PORT || 10010;
  app.connection({ port: port });

  app.register(runner.hapiMiddleware().plugin, function(err) {
    if (err) { return console.error('Failed to load plugin:', err); }
    app.start(function() {
      console.log('try this:\ncurl http://127.0.0.1:' + port + '/hello?name=Scott');
    });
  });
});