API Versioning with Ruby on Rails: Which gems are the best?
API versioning helps to change the behavior of an API for different clients. An API version is determined by an incoming client request and is based on either the request URL or the request headers. There are a number of valid approaches to versioning.
When is the API versioning required?
API versioning can be ignored in certain cases, eg. For example, if an API acts as an internal client or if an API that you have already used experiences some minor changes (for example, adding new fields or new data to the answer).
However, if you make some important changes to your code or the business logic of your app, and those changes affect existing clients, API versioning is the only way to avoid damaging old clients.
How can an API version be specified by the client?
Here is a list of places where API versions are generally stated:
1. URL path parameter:
The API version is inserted in the URL path
HTTP GET:
https://domain.com/api/v2/resources
2. URL Get parameter or request body parameter
HTTP GET:
https://domain.com/api/resources?version=v2
3. Accept headers as versioned media type
HTTP GET:
https: // domain / api / books
Accept:
application / vnd.your_app_name.v2 + json
4. Custom header
HTTP GET:
https: // domain / api / books
API VERSION: 2
There is a continuing debate about how to properly specify an API version.
URLs are not considered ideal for this task because they represent a resource but not the version of that resource. However, this is the simplest approach and is suitable for testing.
A custom header is considered excessive because the HTTP specification already has the Accept header that serves the same purpose.
The header API versioning accepts the best option according to the HTTP specification. However, it is not easy to test such APIs compared to other approaches. Since opening an API URL is not enough, you must write a request with correct headers.
When it comes to which version of an API to choose, most developers agree to use the first API version as the default.
If your API client (iOS / Android device, web browser, etc.) does not specify a required API version, your API must return the very first version of the response, as the only certain assumption is that this client was previously created a versioning. API versioning with Ruby on Rails Rails has a large amount of gems for creating APIs with versioning. Let's take a closer look at their abilities. Versionist This piece of jewelry supports three versioning strategies: HTTP header, URL path, and request parameters. Routes, controllers, presenter / serializers, tests and documentation are namespaces. This isolates the code of one API version from another. This can seem exaggerated because most changes are made to views or serializers.
But it is more correct, since isolating logic within namespaces is a cleaner and more obvious approach than dealing with a mix of different versions within a controller. To automate routine tasks, versionist provides Rails generators to generate new versions of your API and new components within an existing version. It also provides a Rails generator that copies an existing API version to a new API version. However, this does not work according to the DRY approach because it results in code duplication. I have never used these generators before. Normally, I manually create all the needed controllers and serializers.
I also do not copy all the code from the previous version; I only inherit from the previous version control. A major disadvantage of the version gem is that the API version mechanism it provides does not support relapses to the previous version if the specified logic has not been copied to the new version. The jewel expects all the code required to be duplicated in each new release. But if you just have to change one response format, that seems overkill. But this gem is still pretty good. It's lightweight and focuses only on API versioning.
This is nice compared to some gems that dictate certain methods of API versioning (eg rocket_pants and versioncake). Here's an example of versioned routes from the Versionist gem that uses the Accept header with the versioned media type: Namespace: versionist_api do api_version ( Header: { Name: "Accept", Value: 'application / vnd.versionist_api.v2 + json' },
Module: "V2", Defaults: {format :: json} ) do Resources: Books only: [: index ,: create ,: show,: update,: destroy] The End api_version ( Header: { Name: 'Accept', Value: 'application / vnd.versionist_api.v1 + json' }, Module: 'V1', Default: True, Defaults: {format :: json} ) do Resources: Books only: [: index ,: create ,: show,: update,: destroy]
The End The End version cake This gem has a different approach. In most cases, versioning is for API views, and controllers are not namespaced. A nice feature of Versioncake is that it has relapses to earlier versions. Along with path, query param, accept header, and custom header, it also provides the ability to create its own versioning approach that accepts a request object. In this way, developers can specify an API version anywhere in the request in any form.
Because versioncake does not support a controller for each version, it has special methods to access the requested version and version within the instance of the controller. However, this can cause an inexperienced developer to write bad code if it has conditional logic within controllers that depends on those version parameters. In this case, it is better to use the factory pattern where the controller action is implemented as a single object for each version (the interactor gem can be used for this purpose).
Versioncake has a variety of features (see the comparison chart for details), including some exotic features like version devaluation. In one sense, it looks like a complete solution for API versioning; but in another, it may seem a bit hard, as some of its additional features may not be used in generic API use cases. Another disadvantage of Versioncake is that it is sight-oriented. Gems like jbuilder and rabl can be used with versioncake as their templates are saved as views. But more modern and popular gems like active_model_serializers can not be used with versioncake. This may be fine if you prefer to use some parts of the view as sections (for example, if there are Version 1 fields in a Version 2 response); With active_model_serializers you can use the normal inheritance of Ruby classes.
grape
Grape is not just an API versioning tool. It is a REST-like API framework. Grape is designed to run on rack or supplement existing web application frameworks such as Rails and Sinatra by providing a simple domain-specific language to easily develop RESTful APIs.
Regarding API versioning, grape offers four strategies: URL path, Accept header (similar to the versioned media type approach), Accept version header, and Request parameters.
It is also possible to have relapses to earlier versions using the specific code organization described here: http://code.dblock.org/2013/07/19/evolving-apis-using-grape-api-versioning Here's a quick example of API Versioning Fallbacks in Grapes:
And here is a module for the default configuration of the first version:
Module GrapeApi
Module V1
Module defaults
Expand ActiveSupport :: Concern
do included
# This would make the first API version react to the second as a fallback
Version ['v2', 'v1'], using :: header, vendor: 'grape_api'
# ....
The End
The End
The End
And the second version:
Module GrapeApi
Module V2
Module defaults
Expand ActiveSupport :: Concern
do included
# Version "v2", with :: path
Version 'v2' using :: header, vendor: 'grape_api'
The End
The End
The End
For trave_api / base.rb, the second version is installed before the first version. This allows you to process requests for version 2 with V2 logic (if available) or to access version 1.
Module GrapeApi
Class Base