Article

API Versioning with Ruby on Rails: Which gems are the best?

Topic: Business Accounting Software and QuickBooksPublished January 29, 2018

Legacy signals

Legacy popularity: 1,399 legacy views

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?rnHere 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 parameterrnHTTP 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. rnBut 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). rnVersioncake 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. grapernGrape 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 :: Conce rndo 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 :: Conce rndo included # Version "v2", with :: path Version 'v2' using :: header, vendor: 'grape_api' The End The End The EndrnFor 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 http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned I also prefer this versioning approach. Versioned routes with this gem look like this: api vendor_string: "api_versions", Standard version: 1, Path: 'api_versions', module: 'api_versions' Version 1 do Cache as: do 'v1' Resources: Books only: [: index ,: create ,: show,: update,: destroy] Controller: Test, Path: 'test' do get 'some_action' The End The End The End Version 2 do inherit from: 'v1' The End The End The API Version Jewel lets you inherit route definitions from an earlier version. However, this requires that you also have a controller with a specific action for this version. The gem has a generator task (api_versions: bump), which creates controllers for the next version. Controllers generated by these generator controllers inherit from earlier ones. Inheritance seems to be the correct solution by default, compared to the Versionist gem, which makes copies of earlier versions of the controller. But it's not great to make all the controllers for each new API version if you make just a small change to an API response. rnThe better and more logical solution would be if this gem could provide an API fallback mechanism that would directly reuse the logic of the previous API version, but unfortunately API versions do not have such capabilities. acts_as_api This gem is not intended for API versioning, but provides a simple domain-specific langung to define the appearance of model data to be rendered in API responses. However, it is still possible to use it for API versioning. So I experimented with acts_as_api to get versioning of API responses: Class Book

Further reading

Further Reading

4 total

Article

Many health and fitness apps can count steps and calories, but they often fail at the most important part: turning everyday lifestyle data into insights that doctors and patients can actually use. Meal photos, activity logs, and energy expenditure can tell a much bigger story but only if they’re analyzed in a meaningful way over time. Hanoi MH is a health and nutrition AI platform designed to bridge that gap. By analyzing meals and movement, and forecasting BMI and MET tren

January 19, 2026

Article

Financial markets move fast often faster than individual traders or even financial teams can keep up. Stocks fluctuate by the second, crypto moves 24/7, and traditional platforms often overwhelm users with charts, indicators, and raw numbers. What’s missing is clarity. Inveto fills that gap as an AI-powered trading and investment forecasting platform designed to turn complex real-time data into clear insights, actionable signals, and personalized reports. Instead of guessin

January 16, 2026

Article

Why Global Software Development Partners Are Reshaping the IT LandscapernIn a world where digital transformation is no longer optional, companies of all sizes are turning to global software development partners to accelerate innovation, reduce costs, and build scalable tech solutions. Whether it's launching a new product or modernizing legacy infrastructure, having a reliable IT partner can make all the difference. Custom Software Development Is Not One-Size-Fits-AllrnEvery b

December 18, 2025

Article

Most projects don’t fail mid-way—they fail before they start because teams skip the software project discovery phase. Discovery aligns business goals with technical realities, clarifies scope and risks, and sets realistic budgets and timelines. If you want to save time and money, start here. What Discovery IsrnA time-boxed Discovery Phase in software development that turns assumptions into a plan and validates feasibility. Expected outcomes: — Shared problem definition,

October 28, 2025