Trying to Update Open API Spec from 2.0 to 3.0 But YAML Still Evaluates as 2.0. - node.js

I am trying to update my local swagger project from OpenAPI 2.0 to OpenAPI 3.0.
I am getting a ton of errors which imply that I my YAML file is still being evaluated as OAS2.0:
Project Errors
--------------
#/: Missing required property: swagger
#/: Additional properties not allowed: components,servers,openapi
#/paths/~1auth~1info~1firebase/get/responses/200: Not a valid response definition
#/paths/~1posts~1{id}~1comments/get/responses/200: Not a valid response definition
#/paths/~1posts~1{id}~1comments/get/parameters/2: Not a valid parameter definition
#/paths/~1posts~1{id}~1comments/get/parameters/1: Not a valid parameter definition
#/paths/~1posts~1{id}~1comments/get/parameters/0: Not a valid parameter definition
#/paths/~1users~1{id}~1profile/get/responses/200: Not a valid response definition
I have updated swagger-ui-express to the latest version.
Below are the relevant parts of my server.js file:
const YAML = require('yamljs');
const swaggerDocument = YAML.load('./api/swagger/swagger.yaml');
const SwaggerExpress = require('swagger-express-mw');
const swaggerUI = require('swagger-ui-express');
const api = express();
let swaggerConfig =
{
appRoot: __dirname
}
let swaggerOptions =
{
explorer: true
};
api.use('/api/v1/docs/endpoints',
swaggerUI.serve,
swaggerUI.setup(swaggerDocument, swaggerOptions)
);
SwaggerExpress.create(swaggerConfig, function(err, swaggerExpress) {
if (err) { throw err; }
// install middleware
swaggerExpress.register(api);
});
I have updated swagger-ui-express and swagger-express-mw to the latest versions.
But I am still getting the above errors.
I am thinking that the way forward may be to not use swagger-ui-express
and rework my code for swagger-ui but I see online that people seem to
get things working with that npm module.
Any ideas what I am doing wrong?

Related

How to integrate OIDC Provider in Node jS

I tried to Integrate OIDC Provider to Node JS and I have a Sample Code. So, I run this Sample code it's throwing an error(unrecognized route or not allowed method (GET on /api/v1/.well-known/openid-configuration)).The problem is Issuer(https://localhost:3000) this Issuer is working fine. but i will change this Issuer((https://localhost:3000/api/v1/)) it's not working How to fix this Issue and I facing another issue also when I implement oldc-provider in node js. They Routes are override how to fix this issue
Sample.js
const { Provider } = require('oidc-provider');
const configuration = {
// ... see available options /docs
clients: [{
client_id: 'foo',
client_secret: 'bar',
redirect_uris: ['http://localhost:3000/api/v1/'],
true_provider: "pcc"
// + other client properties
}],
};
const oidc = new Provider('http://localhost:3000/api/v1/', configuration);
// express/nodejs style application callback (req, res, next) for use with express apps, see /examples/express.js
oidc.callback()
// or just expose a server standalone, see /examples/standalone.js
const server = oidc.listen(3000, () => {
console.log('oidc-provider listening on port 3000, check http://localhost:3000/api/v1/.well-known/openid-configuration');
});
Error
Defining Issuer Identifier with a path component does not affect anything route-wise.
You have two options, either mount the provider to a path (see docs), or define the actual paths you want for each endpoint to be prefixed (see docs).
I think you're looking for a way to mount, so the first one.

Swageer js doc does not instant update api docs on changes?

I am using swagger-jsdoc
I have setup swagger js docs like below in my app.js
//include swagger js doc
var swaggerJSDoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');
const pathToSwaggerUi = require('swagger-ui-dist').absolutePath()
const swaggerDefinition = {
swagger: '2.0',
info: {
// API informations (required)
title: 'API', // Title (required)
version: '1.0.0', // Version (required)
description: 'Used for api documentation', // Description (optional)
},
host: `localhost:3000`, // Host (optional)
basePath: '/app/v1', // Base path (optional)
};
// Options for the swagger docs
const options = {
// Import swaggerDefinitions
swaggerDefinition,
// Path to the API docs
// Note that this path is relative to the current directory from which the Node.js is ran, not the application itself.
apis: ['./app/v1/docs/*.yaml']
};
// Initialize swagger-jsdoc -> returns validated swagger spec in json format
const swaggerSpec = swaggerJSDoc(options);
app.use('/v1/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
I have certain yaml files which i have written for document the api. I hit the url from browser
localhost:3000/v1/docs
This shows me documented api in swagger ui. But when i make update in any of the yaml files and refresh the page then i don't see updated changes. I have to stop the nodemon process and restart the process again which i do not want to do. So let me know how can i do this?
By default, nodemon looks for files with the .js, .mjs, .coffee, .litcoffee, and .json extensions.
To add other extensions please use the following command:
nodemon -e yaml
For more details, refer to the official docs: https://www.npmjs.com/package/nodemon

How can my client get application configuration from the server when using Webpack?

I'm adding Webpack to a Node/Express app that previously used RequireJS. When the client needed some configuration from the server, we previously used a custom Express route that retrieved specific configs as JSON:
server/index.js - Set up Express routes for config files
const app = express();
const configRouter = express.Router();
configRouter.get('/some-config.json', (req, res) => {
const someConfig = {
prop1: getProp1(),
prop2: getProp2()
}
res.json(someConfig);
}
app.use('/config', configRouter);
client/controller.js - Use/config/some-config.json during initialization
define(['text!/config/some-config.json'], function(SomeConfig) {
// do something with SomeConfig
});
But removing RequireJS means I can no longer retrieve the JSON this way as a dependency. And it's not static JSON either, so it's not as simple as just placing it alongside client code and importing it.
So what is the best way to do this with Webpack? Any help greatly appreciated. Thanks!

NodeJS/Express API versioning

I'd like to set up an API versioning, similar to how Stripe does it but I'm not quite sure how to make express do what I need. https://stripe.com/docs/api#versioning
What I'm looking for is, the proper route would be something like:
/api/v1/call
The kicker is, I'd like them to pass in a version revision like stripe allows, so if they sent a header like "API-Version: 2015-08-15", it would map to that specific version of the major version. So, v1 but the version updated on 2015-08-15.
Essentially, if there is an update to the API call that is not backwards compatible, I'd roll a new version for that particular call. Express would be smart enough to know that if a version isn't passed, use the latest. If a version is passed, use the latest version for each call up until the version date.
I'd assume the directory structure would be something like:
/router/
/router/v1
/router/v1/call
/router/v1/anotherCall
And maybe in the call directories, there is a index that checks for the header version and uses the proper file.
So maybe for instance
/router/v1/call/index.js
/router/v1/call/20150810.js -- First version
/router/v1/call/20150815.js -- Updated version that isn't backwards compat.
Thoughts? Ideas?
If you are managing version in routes(url) and client sends version in headers then express doesn't provide any elegant way to handle versioning. Also, doing versioning in routes is not restful.
I wrote an simple npm module to solve this problem. https://www.npmjs.com/package/express-routes-versioning
Express routes versioning
Module allows individual routes to be versioned separately. It is agnostic about specific versioning strategies and allows the application to set the version, so you should be able to parse version from headers and set it to req.version in a middleware. It supports semver versioning format and symbols to map multiple versions to single function.
Sample code on how it works.
var app = require('express')();
var versionRoutes = require('express-routes-versioning')();
app.listen(3000);
app.use(function(req, res, next) {
//req.version is used to determine the version
req.version = req.headers['accept-version'];
next();
});
app.get('/users', versionRoutes({
"1.0.0": respondV1,
"~2.2.1": respondV2
}));
// curl -s -H 'accept-version: 1.0.0' localhost:3000/users
// version 1.0.0 or 1.0 or 1 !
function respondV1(req, res, next) {
res.status(200).send('ok v1');
}
//curl -s -H 'accept-version: 2.2.0' localhost:3000/users
//Anything from 2.2.0 to 2.2.9
function respondV2(req, res, next) {
res.status(200).send('ok v2');
}
By default, if the client version doesn't match the version provided in the server, module servers the latest version callback available in that route. This behavior can be overridden by providing an additional callback. More info and source code available at https://github.com/Prasanna-sr/express-routes-versioning
This how I'm handling versioning. Basically you create a new router object and use app.use so that only /api/v1 routes are sent to it. I then use a "fall through" route which catches anything which didn't match and returns a unknown command message. I also renamed the res.json function so that I can add APIversion = 1 to each object that went out (That's in the router.use function call).
Whenever I have a v2 api I'll do this exact same thing but create a new file and use a different app.use path. See below:
app.js
....
app.use('/api/v1', require('./api1.js'));
....
api1.js
var express = require('express');
var router = express.Router();
router.use(function (req, res, next) {
res._json = res.json;
res.json = function json(obj) {
obj.APIversion = 1;
res._json(obj);
};
next();
});
/* ADD ALL YOUR ROUTES HERE */
//Done - catch all - return command failed
router.get('*', function (req, res) {
res.status = 404;
res.json({
success: false,
message: 'Unknown command'
});
});
module.exports = router;
https://medium.com/#vgjohn/node-js-api-versioning-with-totoro-node-c2ea1ef3dfba
There's a small package called totoro-node that helps deal with route management for api versioning. It might help to solve some of the problems you're facing. You just write a simple api definition like this and you can control which endpoints or api versions to deprecate or inherit into subsequent api versions. https://www.npmjs.com/package/totoro-node
var app = express()
app.use('/api', totoro.rain({
v1: {
"/oAuth": {
method: "GET",
deprecated: true,
endpointImplementation: routes.authRoutes.oAuth
},
"/ssoToken": {
method: "GET",
endpointImplementation: routes.authRoutes.sso
}
},
v2: {
"/ssoToken": {
method: "GET",
endpointImplementation: routes.authRoutes.sso
}
}
}))
I think you could set a middleware before all your routes to check headers.
app.use("*",function (req,res,next) {
var headers = req.headers
//Process
req.apiVersion = "version"
next()
}
//all your routes
this is a example , but you could manipulate headers in your router instance and then pass req to other route
//v1/call/index.js
//all your routes
app.use("/v1/call",function (req,res){
var version = req.apiVersion;
//execute something depending on version
})

Restify: API version in URL

Currently under development of API with restify and still cannot get used to specifying the API version in headers. It just doesn't seem very user friendly.
Is there any way for version to be part of url?
Example would be:
http://domain.com/api/v1/action
Or even better in my case:
http://api.domain.com/v1/action
Thanks
Also you can use Restify to define your versions:
var server = restify.createServer({
name: 'myAPI',
versions: ['1.0.0', '2.0.0']
});
Then using this middleware with server.pre:
server.pre(function (req, res, next) {
var pieces = req.url.replace(/^\/+/, '').split('/');
var version = pieces[0];
// only if you want to use these routes:
// /api/v1/resource
// /api/v1.0/resource
// /api/v1.0.0/resource
if (!semver.valid(version)) {
version = version.replace(/v(\d{1})\.(\d{1})\.(\d{1})/, '$1.$2.$3');
version = version.replace(/v(\d{1})\.(\d{1})/, '$1.$2.0');
version = version.replace(/v(\d{1})/, '$1.0.0');
}
if (semver.valid(version) && server.versions.indexOf(version) > -1) {
req.url = req.url.replace(version + '/', '');
req.headers['accept-version'] = version;
}
return next();
});
Finally, in your routes you can do something like this:
server.get({ path: '/resource/:id', version: '1.0.0' }, function () {
// send object in version 1.0.0
});
server.get({ path: '/resource/:id', version: '2.0.0' }, function () {
// send object in version 2.0.0
});
Examples:
http://api.domain.com/resource/10
http://api.domain.com/2.0.0/resource/10
http://api.domain.com/1.0.0/resource/10
The above examples follow the standards, because if version is not specified through header or url, shows the last version.
UPDATE:
I made a plugin to have API versions in URL:
https://www.npmjs.com/package/restify-url-semver
People are correct that it's not supported by restify, but I thought I'd throw my solution to this problem into the mix. I'm doing something like this (warning, untested code to follow):
After I create a server, but BEFORE I declare the routes, I register a custom parser to translate the url-style version specifier into an HTTP-style specifier:
server.use(versionParser);
And versionParser.js looks something like this:
var semver = require('semver');
var restify = require('restify');
module.exports = function (req, res, next) {
// we expect every request to have the form "/api/[api-version]/..."
// verify that the api-version is a valid semver value
var urlPieces = req.url.replace(/^\/+/, '').split('/');
var api = urlPieces[0];
var apiVersion = urlPieces[1];
if (api !== 'api' || !semver.valid(apiVersion)) {
return next(new restify.InvalidContentError({message: "Invalid Version Specifier"}));
}
req.header('Accept-Version', apiVersion);
return next();
}
This way, the restify routes can inspect the Accept-Version header as they do naturally.
Sidenote: The semver part is probably not relevant to this answer, but I wanted to verify that the API version in the URL was a valid semver value, as it allows flexibility in the URL values such that a user could take advantage of restify's flexibility in version specifiers.

Resources