Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js REST API versioning the right way?

I would like to manage my REST API based on URL version specifying.

For example:

api.mydomain.com/v1/rides/
// will return all rides based on v1.

api.mydomain.com/v2/rides/
// will return all rides based on v2 (probably with some braking changes).

api.mydomain.com/rides/
// will return all rides based on v2, since v2 is the newest.

Thats awesome.

Before we get started dealing with the practical way of handling this, we should talk about the logical "default newest versioning" - I mean, if user does not going to specify any kind of version, should I serve him with the newest version or throw a 404 not found error?

Should I oblige the user for specifying an API version?

If I do, is there any standard of "parsing" the specific / newest version?

I tell you why im concern about this: Lets say that "Dan" have app installed which relays on the newest API endpoint (V1 for example), then I release V2 which has braking changes. Since Dans "listens" to the newest version by default, Dans app is going to be crashed.

That is not a good behaviour at all. Maybe should I prevent using the "default newest versioning"? Maybe should I use Dans app to listen for a specific version, while remote developers accessing my API as a web service can have the privilege to choose between specific version or the newest by default?

Is there any standard?

**

Now lets talk practically. Lets say that I have a router handling those requests, maybe something like this:

// app.js file

app.use((req, res, next) => {
  try {
    require('../resources/' + req.url.split('/')[1] + '/' + req.url.split('/')[1] + '-router')(app);
    next();
  } catch(err) {
    dep.cast(res, 404, new Error("Not Found"));
  }
});

And some handler, like this:

// resources/rides/rides-router.js file

module.exports = function(app) {

  // GET ride - select a ride
  app.get("/v1/rides/:id", dep.verifyToken(), require('./api/v1/get-ride'));
  app.get("/v2/rides/:id", dep.verifyToken(), require('./api/v2/get-ride'));

  // POST ride - insert a new ride
  app.post("/v1/rides", dep.verifyToken(), require('./api/v1/set-ride'));

}

As you can see, I have handler which sends the requests to the specific divisions in the API, split by V1, V2, etc..

It makes me wonder if its right to have the same page containing the same function over and over in different folders, one for V1 and one for V2. Ofcourse, with some braking changes, but they are probably going to be similar. Is not it bordering with repetitive code?

Look at the project structure:

enter image description here

What do you think about this?

like image 774
Raz Buchnik Avatar asked Jul 25 '18 07:07

Raz Buchnik


People also ask

What is the most common method of versioning a REST API?

There are several methods for managing the version of your API. URI path versioning is the most common.

What is API versioning in node js?

Web Dev. Chameera Dulanga. February 14, 2022. Software versioning is the process of assigning a unique identifier for a specific state of a software application, API or library. As developers, it is essential to follow a formal convention for versioning since it helps to communicate the changes and their impact.


2 Answers

Instead of adding version in every route you can add it in app level. So It won't be tightly coupled with API route.

import * as express from 'express';

// v1/get-ride.js
const router = express.Router();
router.post('/rides/:id', dep.verifyToken(), (req, res) => {
    // Your code
});
app.use('/v1', router);


// v2/get-ride.js
const router = express.Router();
router.post('/rides/:id', dep.verifyToken(), (req, res) => {
    // Your code
});
app.use('/v2', router);
like image 70
Rahul Sharma Avatar answered Sep 21 '22 22:09

Rahul Sharma


I would recommend using node-express-versioning module instead.

It would help you to support multiple versions without changing the url of API, just send the version of API and direct the call to that version route-controller.

*

*//version taken out from header

    app.use(function(req, res, next)
    {
       req.version = req.headers['accept-version'];
       console.log(req.version);
       next();
    });

    //version path defined

    app.use('/api', versionRoutes({  
       "1.0.0": respondV1,
       "2.0.0": respondV2
    }));

    function respondV1(req, res, next)
     {   
        app.use('/api',routeV1);
        next();
     }
    function respondV2(req, res, next)
    {
       app.use('/api',routeV2);
       next();
    }*

*

like image 20
Pragyanshu Sharma Avatar answered Sep 23 '22 22:09

Pragyanshu Sharma