February 20, 2017
Rails dominates Ruby web frameworks: the next most popular framework, Sinatra, has 5% of the popularity of Rails. However, that doesn't mean non-Rails frameworks like Sinatra and Grape don't have their place.
When does it make sense to step away from
ActionController and use another framework? What are the sweet spots and gray areas for these frameworks?
I'll explore these questions below.
Sinatra, released in the fall of 2007, was the first of the non-Rails web frameworks to gain traction. Its focus on quickly creating web apps with minimal effort carved out a niche versus the Rails monolithic approach. A small Sinatra app can easily be contained in a single file, which is a sharp contrast to a Rails app.
With its first release in late fall of 2010, Grape was the next web framework to gain significant traction. Grape is an "opinionated framework for creating REST-like APIs in Ruby". In the same way that Rails conventions help you quickly build an MVC app, Grape's conventions help you build a robust REST-like API in Ruby.
Rails::API was released in the spring of 2012. Rails::API loads a subset of the Rails stack for apps that only generate JSON content, skipping out on middlewares that don't apply to API apps (examples: cookie, flash, and session management). Rails::API started as a stand-alone gem, but with the release of Rails 5 in the summer of 2016, its now included by default in Rails.
There are other alternative web frameworks in Ruby (see "Rails alternatives in 2016"), but their usage is significantly lower than Sinatra. For simplicity, we won't discuss those in this article.
Sinatra, Grape, and Rails::API have sweet spots and overlapping usage scenarios. Let's go over some questions that can identify which framework might be the best fit for your scenario.
If you are building a simple web app, you may think you don't need the special sauce that Rails provides. However, just like peeling away the the layers of an onion, you start to realize that even simple apps require decisions that Rails has already made for you.
For example, if you choose Sinatra or Grape for an initial version of an app, you'll need to think about:
In short, when you don't go Rails, you'll need to make some decisions and have some opinions. If you are building an app as part of a team, this can add a layer of complexity and differing opinions on direction that don't exist with Rails' configuration-over-convention approach.
For these reasons, I typically suggest starting with a Rails app and breaking out services when there's a clear need and scope.
Sinatra, Grape, and Rails::API can all easily service JSON content. However, if it's possible your app could grow beyond simply returning JSON responses (ex: render HTML content, have interactive forms, users sessions, etc) you can rule out Grape. Grape adds significant special sauce to delivering JSON APIs...and that's its sole focus.
Thanks to Rack's support for mounting apps, you aren't stuck with a rewrite if the scope of your app changes and your chosen microframework begins to get outside its sweet spot. You can easily mount Grape and Sinatra apps within a Rails app, or even mount a Grape app alongside a Sinatra app.
While Sinatra and Rails::API easily serve JSON content, there's a lot more than JSON when building public-facing or highly used API. Just like Rails adds conventions for Rails apps, Grape adds conventions for JSON API apps:
Grape emerges as a clear choice when you outgrow a roll-your-own approach to an API. The conventions it covers make it easier for a team of developers to have a clear understanding of best practices that don't exist in custom API apps.
These benchmarks from November 2016 generated by Eugene Melnikov include comparisons of Sinatra, Grape, and Rails::API. Benchmarks can vary widely from real-world use cases, but Sinatra and Grape clearly outperform Rails::API:
I'd view these with some caution: Rails::API still contains a significant amount of middlewares that may be required in a production Sinatra or Grape app. These middlewares add overhead.
There are areas where the decision between frameworks isn't clear cut. Some of these areas:
There are some sweet spots for each of these frameworks:
Want more Ruby insights like this delivered monthly to your inbox? Just put your email into the sidebar form.