Restify: API version in URL
Asked Answered
E

2

8

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

Egad answered 26/1, 2014 at 15:59 Comment(4)
I think that apart from just declaring those routes yourself (app.get('/v1/action', ...)), Restify doesn't support this sort of scheme.Binns
@Binns hm that's what I thought so.. too badEgad
It seems like it might be easier to do something like /api/action?v=1, though I have yet to figure out a graceful way to handle this.Kragh
I think using it as a part of url is better than as a parameter.Egad
T
19

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:

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

Terribly answered 17/4, 2015 at 17:54 Comment(3)
Thanks for great answer would that also work with versions as "v1", "v2" etc?Egad
You can get pieces[0] and then transform it to a valid semver, e.g. v1 to 1.0.0, or v1.0 to 1.0.0, or v.1.0.0 to 1.0.0Mohur
Now you can use with v1, v2, v3, etc. and add with dots v1.0, v2.0, v3.0, v1.2.3, etceteraMohur
M
4

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.

Mraz answered 21/2, 2014 at 1:41 Comment(3)
Injecting the request, interesting. I think you would have to do a tiny bit more work to take care of cases when people actually specify the version header, and also need a bit of thought that restify supports versions in format x.x.x but otherwise, good and effective answerEgad
@Tom Good thoughts. semver.valid does enforce that it's x.x.x, so I think that would cover it. As for checking to see if they initially put it in the Accept-Version header, that's a good thought that I could see being especially useful in the case of a migration from one format to the other.Mraz
Honestly I haven't use semver yet so not exactly sure what does it do. But anyways in my case, it would be rather easy without it as well. I don't see when I would be using other version than 1, 2, etc. So simple version+'.0.0' would doEgad

© 2022 - 2024 — McMap. All rights reserved.