@noveo/swagger-middleware

0.4.0-beta • Public • Published

@noveo/swagger-middleware

The package is a wrapper for swagger-express-middleware@1.1.1 It helps you to deal with swagger@2.0 defined apis. It does NOT support openapi@3

install

npm i --save @noveo/swagger-middleware

or

npm i --save git+https://gitlab%2Bdeploy-token-10:y6fu7AnyXgsxn1sJ6zxz@gitlab.noveogroup.com/devteam/back/swagger-middleware.git

usage

const swagger = require('@noveo/swagger-middleware');

// Load modules
const loaded = await swagger.loaders.byPackageJson({
  folders: ['essences', 'scenarios'],
  root: __dirname,
  logger: log.child('modules-loader'),
  baseApiPath: resolve(__dirname, './api.yml'),
  app: { name: appName, version },
  server: { protocol, host, port }
});

const app = express();

// Init secureCollection for adding secure adapters 
const secureCollection = swagger.secureCollection;
// Adapters presets for security
const adapters = swagger.adapters;

// Initiate adapter with apiKey presets to secureCollection, passing function secure ad 2nd parameter for checking security
await secureCollection.add(adapters.apiKey, {
    check(key) {
        return key === 'authKey'
    }
});

// Initiate adapter with basic auth presets to secureCollection, passing function secure ad 2nd parameter for checking security
await secureCollection.add(adapters.basic, {
    check(email, password) {
        const user  = db.users.findOne({email}, ['password', 'salt']).lean();
        
        if (! user) {
            return false;
        }
        
        const cryptoPassword = sha512(password, user.salt);
        
        return (cryptoPassword === user.password);
    }
});


// Init Doc UI and schema get endpoint
app.use(api.basePath, middleware.docs({
  jsonPath: '/swagger.json',
  yamlPath: '/swagger.yaml',
  ui: {
    baseUrl: '/ui/',
    docUrl: `${api.basePath}/swagger.json`
  }
}));

app.use(
  // Checks out the correctness of json-response via the provided 
  // OpenAPI 2 or OpenAPI 3 schema
  middleware.validateResponse(),  
  // Annotates each request with all the relevant information from the Swagger definition. 
  // The path, the operation, the parameters, the security requirements. 
  // They’re all easily accessible at req.swagger. It just parses parameters definitions from the API, not the values.
  // Values are parsed by parseRequest
  middleware.metadata(),    
  // Initiate secure middleware passing secureCollection to it
  middleware.secure(secureCollection),
  // Adds the appropriate CORS headers to each request and automatically responds to CORS preflight requests,
  // all in compliance with your Swagger API definition.
  middleware.CORS(),
  // Parses incoming requests and converts everything into the correct data types, 
  // according to your Swagger API definition.
  // It uses body-parser, cookie-parser, multer
  middleware.parseRequest(),
  // Ensures that every request complies with your Swagger API definition, 
  // or returns the appropriate HTTP error codes if needed
  middleware.validateRequest(),
  // You may put handlerStorage made by modules loader or by your hands
  middleware.handler({
    handlerStorage: loaded.handlerStorage
  }),
  // It is for mocks
  middleware.mock(),
);

app.listen(8000);

QnA

Why do we use our docs middleware? Why don't we use swagger-express-middleware files middleware

Our middleware provides not only json api definition, but It provides yaml definition too. Then our middleware provides api definition explorer UI. You may use files middleware if you need or if you find docs middleware incompatible for you or insecure etc. Please, notice the maintainer if you have any issues

Debug and logging

It uses debug with main prefix as swagger as default logger ;

API

Exported lib is an object with two properties: initMiddleware and loaders

initMiddleware(options) ⇒ Promise.<initMiddlewareResponse>

It is a wrapper for swagger-express-middleware#createMiddleware. It initializes middlewares

Kind: Function
Returns: Promise.<initMiddlewareResponse>

Param Type Mandatory Default Example Description
options.apiDef Object or String REQUIRED './api.yml' A Swagger Object, or the json file path or URL of your Swagger API. It is forwarded to swagger-parser.dereference
options.app express#Router REQUIRED express() An Express app It is forwarded to swagger-express-middleware#createMiddleware method
options.logger loggerInstance Optional debug with main prefix as swagger noveoLogger.getLogger('swagger') Logger instance
thisisforcellwithyeah thisisforcellwidthyeah

initMiddlewareResponse

middleware is initialized by swagger-express-middleware#createMiddleware. Then some middleware factories like docs and handler were added to middleware. api and parser are from swagger-express-middleware#createMiddleware. They are forwarded to callback as third and fourth params, but it is not documented.

Kind: Object

Property Type Description
middleware middlewareFactories Container with swagger-express-middleware middlewares and our middlewares
api Object It is a Swagger Object, dereferenced by swager-parser.dereference
parser SwaggerParser It is a Swagger Object, dereferenced by swager-parser.dereference

middlewareFactories

Kind: Object extends instance of swagger-express-middleware Middleware class

Property Type Description
docs docsMiddlewareFactory Factory for creating docs middleware
handler handlerMiddlewareFactory Factory for creating handlerMiddleware
<String> Other factories of swagger-express-middleware

docsMiddlewareFactory(options) ⇒ express.Router

Factory for middleware, which creates routes with json and yaml api definitions and ui documentation explorer. The recommended way of usage is to hang it on express route defined as application basePath. For example, app.use('/base-path', middleware.docs())

Kind: Function
Returns: express.Router instance

Param Type Mandatory Default Example Description
options.jsonPath String Optional undefined '/swagger.json' Path for json api definition route. Route does not initialize if the option is falsey
options.yamlPath String Optional undefined '/swagger.yaml' Path for yaml api definition route. Route does not initialize if the option is falsey
options.ui.baseUrl String Optional undefined '/ui/' Url for hanging on some ui routes for html, css, js files. Explorer UI does not initialize if the option is falsey
options.ui.docUrl String Optional 'https://petstore.swagger.io/v2/swagger.json' '/base-path/swagger.json' Url could be relative or absolute. It should contains json api definition. Explorer UI helps to explore the api definition
options.router express.Router constructor Optional express.Router of express@4.16.4 express.Router You may put your own express.Router class of your express version
options.api Object Optional api produced by initMiddleware { swagger: '2.0', ... } You may put your own dereferenced api def object
options.logger loggerInstance Optional logger put to initMiddleware or debug with main prefix as swagger noveoLogger.getLogger('swagger') Logger instance
thisisforcellwidthyeh thisisforcellwidthyeh thisisforcellwidthyeah

Notice

Use options.ui.baseUrl with finishing slash like /ui/ but not like /ui. It uses wildcard like /ui/* for express routing and swagger-ui-dist package, that uses relative paths like ./swagger-ui.css. So, the relative with /base/ui (without finishing slash) would be /base/swagger-ui.css, which is incorrect. The relative with /base/ui/ will be /base/ui/swagger-ui.css, which is correct.

handlerMiddlewareFactory(options) ⇒ express.Middleware

It is a factory for producing a middleware that handles a handlers which are indexed by operationId. It chooses an operationId by req.swagger data provided by middleware.metadata middleware. It fails without middleware.metadata middleware.

Kind: Function
Returns: express.Middleware

Param Type Mandatory Default Example Description
options.handlerStorage Map REQUIRED new Map([['operationId', (req, res, next) => {}]]) A storage of operations handlers
options.logger loggerInstance Optional logger put to initMiddleware or debug with main prefix as swagger noveoLogger.getLogger('swagger') Logger instance

validateResponseFactory(options) ⇒ express.Middleware

It is a factory for response validation

Kind: Function
Returns: express.Middleware

Param Type Mandatory Example Default Description
options.schema Object Optional { swagger: '2.0', ... } api produced by initMiddleware You may put your own dereferenced api def object
options.logger loggerInstance Optional noveoLogger.getLogger('swagger') logger put to initMiddleware or debug with main prefix as swagger Logger instance

loaders

Container for loaders. We have one implemented loader. Each loader should be a Function, that returns Promise.<loaderResponse

Kind: Object

Property Type Description
byPackageJson byPackageJsonLoader Loader with algorithm based on package.json file

loaderResponse

An object that loader should resolves

Kind: Object

Property Type Description
api Object Dereferenced api definition object
handlerStorage Map<String,express.Middleware> A storage of operations handlers

byPackageJsonLoader(options) ⇒ Promise<loaderResponse>

Kind: Function
Returns: Promise<loaderResponse>

Param Type Mandatory Default Example Description
options.folders String[] Optional [] ['essences', 'modules'] Array of paths for modules directories. Paths are relative to the root path defined in the root option
options.root String Optional process.cwd() './home/web/app/modules-container' It is path to root directory of modules.
options.baseApiPath String REQUIRED './home/web/app/swagger.yml' Path to the api def with base api information
options.app.name String Optional undefined 'my-app' App name could be merge into api def info.title field
options.app.version String Optional undefined 'v0' App version could be merged into api def info.version field
options.server.protocol String Optional undefined 'https' Server protocol could be merges into api def schemes#0 field
options.server.host String Optional undefined 'localhost' Server host partly could be merged into api def host field
options.server.port String or Number Optional undefined '8000' Server port partly could be merged into api def host filed
options.logger loggerInstance Optional debug with main prefix as swagger noveoLogger.getLogger('swagger') Logger instance
thisisforcellwidth thisisforcellwidth thisisforcellwidth

How it loads modules

  • It looks for directories into the folders you pointed as folders option
  • It looks for files package.json in the directories
  • It considers package.json as object of byPackageJsonLoader-packageDef type
  • It loads api definitions from files described in api definition options
  • It loads controllers from files described in api actions options
  • If it finds valid package.json it loads the module as defined in package.json. That means it advances common api definition with module routes.

byPackageJsonLoader-packageDef

It is an object that describes how to load module using byPackageJsonLoader

Kind: Object

Property Type Example Description
name String 'Module name' Name of the module
api[].definition String './api.yml' Path to the module api definition. It is forwarded to swagger-parser to .dereference() method. Look at swagger-parser if you have any questions
api[].actions String './controllers.js' Path to the js file that exports object with props keys like operationIds in the module api definition. And props values should be route controllers which implement such interface as function (req, res, next). Yes, it should be handlers like for express and for swagger-express-middleware. Each should responds with res.send() or res.json() or forwards errors with next(err)
thisisforcellwidth thisisforcellwidth

loggerInstance

Kind: Object instance of logger with defined methods

Property Type Description
info logMethod logger on info level
debug logMethod logger on debug level
warn logMethod logger on warn level
error logMethod logger on error level
thisisforcellwidth

logMethod(msg)

Kind: Function Returns: void

Param Type Mandatory Default Example Description
msg String Optional '' 'controller is requestd' Message for logging
thisisforcellwidth

secure

Kind: Function Description Main secure middleware, checking every response for contain security Returns: void

Param Type Mandatory Description
secureCollection Object REQUIRED Object that contains initiated secure functions

secureCollection

Kind: Factory Description Factory that used for adding/getting and store all security functions that passed to her. Returns: void

Functions Example Description
add secureCollection.add(adapters.apiKey, {check => {}}) Add adapter to registeredAdapters list
get secureCollection.get(apiKey) Get adapter by name from registeredAdapters list

adapters

Kind: Object Description Collection that contains auth type templates like apiKey,basicAuth. Each element of collection is an object and contains adapter defaultType and init function Returns: Object with adapters

Param Type Example Description
apiKey Object {defaultType: 'apiKey', init() => {} apiKey auth object
basic Object {defaultType: 'basic', init() => {} basic auth object

TODO and questions

  • Add logging to responseValidation
  • Check with security definitions
  • Add tests
  • Put secure and validateResponse into middlewareFactories description (documentation)
  • Put secure and adapters into Index (documentation)
  • Update swagger-express-middleware to v2.0.0

Readme

Keywords

none

Package Sidebar

Install

npm i @noveo/swagger-middleware

Weekly Downloads

2

Version

0.4.0-beta

License

MIT

Unpacked Size

362 kB

Total Files

33

Last publish

Collaborators

  • koluch
  • zlblden
  • noobikz0r
  • noveogroup
  • agsh
  • noveo-adobrodiy
  • adergaev