This process will allow you to use Swagger Yaml files for validation. I've only tried this with REST endpoints, however it seems this should work with real-time sockets as well.
You'll need a few npm packages.
yarn add swagger-tools
yarn add js-yaml
First, we will create a swagger.js
file in the /src
directory.
/* eslint-disable no-console */
const path = require('path');
const yaml = require('js-yaml');
const fs = require('fs');
const swaggerTools = require('swagger-tools');
const featherErrors = require('@feathersjs/errors');
let swaggerMetadata = function (req, res, next) { next(); };
let swaggerValidation = function (req, res, next) {
console.warn('Swagger initialization did not complete successfully');
next();
};
function init() {
const app = this;
const config = app.get('swagger');
let pathToDef = (config && config.file) ? path.resolve(__dirname, config.file) : 'swagger.yaml';
let swaggerDoc = {};
try {
swaggerDoc = yaml.safeLoad(fs.readFileSync(pathToDef, 'utf8'));
swaggerTools.initializeMiddleware(swaggerDoc, (middleware) => {
// Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
swaggerMetadata = middleware.swaggerMetadata();
// Validate Swagger requests
swaggerValidation = middleware.swaggerValidator();
});
} catch (e) {
throw new Error(e);
}
}
function validate(context) {
const req = {};
req.method = (context.method === 'create') ? 'post' : req.method;
req.method = (context.method === 'remove') ? 'delete' : req.method;
req.method = (context.method === 'update') ? 'put' : req.method;
req.method = (context.method === 'find') ? 'get' : req.method;
req.method = (context.method === 'patch') ? 'patch' : req.method;
req.url = '/' + context.path;
req.headers = context.params.headers || {
'Accept': 'application/json',
'Content-Type': 'application/json'
};
req.body = context.data;
const res = {
send: (value) => {
// This should never be called
},
status: (value) => {
// This should never be called
}
};
swaggerMetadata(req, res, () => {
swaggerValidation(req, res, (errors) => {
if (errors) {
throw new featherErrors.BadRequest(errors.results);
}
});
});
return context;
}
module.exports = {
init,
validate
};
What you see happening here is an init method that sets up the swagger necessary methods.
And then I've exposed a validate
method as a hook method.
The swagger.js will look in the /config/defaults.json
file for an entry for swagger.
"swagger":{
"file": "swagger.yaml"
},
If you don't include this, it should fall back to looking for the file swagger.yaml
in your root /src
directory.
Inside the app.js file (or where you configure Feathers).
const swagger = require('./swagger').init;
Then place in the configuration stack (I put it right above the middleware)
app.configure(swagger);
Within your services, now all you need to do is add in the hook.
const validateSwagger = require('../../swagger').validate;
The path here follows the feathers-cli app structure, you might need to adjust to point to your custom swagger.js validation hook code.
Now you can use that hook like any other.
{
before: {
all: [validateSwagger]
}
}
The reason I did all this is so that I could generate my documetation using the swagger editor at https://editor.swagger.io You can clone the repo and run it locally as well. https://github.com/swagger-api/swagger-editor
Just save/export your .yaml file into your project directory and make sure your file settings match.
I just threw this together and has no unit tests or extensive use testing. There might be a few odd things that need to be fixed up.
In addition, I'd like to get the swagger UI running. Normally it creates a path off the express app, however I think in this case I'm going to launch a separate express instance to host it. I'd love suggestions.