Search code examples
javascriptnode.jsrestversioning

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 breaking changes).

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

That's 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 go 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 to specify an API version? ***

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

I tell you why I'm concern about this: Let's say that "Dan" has an app installed which relies 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, Dan's app is going to crash.

That is not a good behavior at all. Maybe should I prevent using the "default newest versioning"? Maybe should I use Dan's 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 let's talk practically. ** Let's 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 a handler which sends the requests to the specific divisions in the API, split by V1, V2, etc...

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

Look at the project structure:

enter image description here

What do you think about this?


Solution

  • 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);