Which framework to choose for Ruby API

Not so long ago I had a chance to share my experience with Grape framework at the Ruby meetup in Berlin. In this article I’ll show you what I presented there.

My team develops a Single-Page Application. Which means we do not mix frontend apples and backend oranges. So the only thing left from the backend is its API, there’s no presentational logic at all. More than that, we’re working exceptionally fast. Designers create concepts, conduct user testing, send everything to development and we create it, start beta testing. If the feedback is positive, we leave everything as it is, if not – remove it or rewrite. As you can see, it’s highly important for us that the framework won’t hinder the work process, but help us and have all the basic features we need. What is also crucial is that the framework shouldn’t restrict our right to bring even our most unconventional ideas to life.

We choose Ruby, as the whole team is familiar with it to some extent. And whatever some non-believers say, it’s still the best language for rapid prototyping and entering the market. Not so long ago I had a little bet with my friend and also a Golang developer about who can create a simple API with a database quicker. We wanted to know which language is faster concerning the development process of a web app. Well, obviously it was Ruby, otherwise I wouldn’t give this example to you :) I don’t want to downplay Go’s significance in any sense, but these languages are completely different in many ways.

Don’t know what an API is? Then start with What is API in web apps and why you need it.

Choosing a framework

Having chosen the language, now we need to choose a framework. Well, what do we have here? Ruby on Rails! Um... Well, DHH, we really appreciate what you’ve done, but let’s look around a little, maybe we’ll find something else.

If you, just like me, have been working with Ruby for a relatively long time, you’re so fed up with it, I guess. For example, if the developer’s opinion about architecture and the framework do not essentially coincide, the framework won’t let you follow the principles which are, in your opinion, fundamental for building a sustainable and flexible system. Let me remind you that I don’t want to throw rotten tomatoes at Rails. The apps written using it might start smelling if you’re not sure what exactly to do with them. That’s why you need to know that the result is in the developer’s hands only. The unfortunate thing is that most of them don’t really care about architecture. Our does care though, but we decided to search for other options anyway. Here’s the short list:

  • Grape
  • Hanami
  • Roda
  • Rails API
  • Sinatra

Those are our requirements for the framework:

  • A fair number of out of the box features;
  • Versioning;
  • The amount of time it’s been on the market;
  • Performance;
  • Our personal preferences. That would be a lie to say they weren’t important.

Out of the box features

There are some basic features, without which any API is of no use at all. Parameter validation, Cross Origin Resource Sharing (CORS) support and exception handling are the basic ones.

It’s a safe bet to say that Rails API has all these features as it’s a part of the same ecosystem.

On the contrary, Sinatra is completely different, as it has nothing of the above %) You can obviously build an architecture you want using it and add any Gems, but for me it is one huge disadvantage which outweighs all the advantages. I worked with Sinatra and even built some stuff with it more than once, but for the product we’re working on now we want something feature-rich. All other frameworks are somewhere in between, meaning they have both out of the box features and additional Gems, so let’s just skip them.

Versioning

When you’re creating an API, you can add versioning at any time. But if you don’t do it at the beginning, it might be a pain in the neck doing it later. It’s crucial for our team to have an opportunity to change an API at any time, but to leave the old one intact. Of course, all the frameworks we’re talking about right now have versioning, but every one is different in some way.

Sinatra, Hanami, Rails API:

namespace '/api/v1' do
  # routes goes here
end

Roda:

r.on "api" do
  r.on "v1" do
    r.is "users" do
      r.get do end
      r.post do end
    end
    r.get "comments" do end
  end
end

Grape:

version 'v1', using: :path

In my opinion the Grape’s way is not the cleanest concerning inner logic, but the most convenient and readable. Moreover, besides url(path)-based versioning, you can use the types based on parameters and headers.

The time on the market

This point acts as an indicator that the framework wasn’t built on the fly by some student. Time test is crucial in the software world.

Grape

Was released in 2010 and had 4 merged pull requests in January according to the GitHub analytics.

Rails API was released in 2012 and had 85 merged pull requests in January. Keep in mind that the Rails API repository was merged with the main Rails one in 2015, so they share these pull requests. That’s no surprise, as Rails is dominant on the Ruby frameworks market.

Sinatra

Kind of a veteran among the rookies. It was released in 2008 and it has been getting updates since then, even though it might seem that it doesn’t need any. It had 3 pull requests in January. However, to me it seems that it haven’t had any major updates for the last five years, but I didn’t dig deeper so I might be mistaken.

Hanami

A new brilliant framework, which was released in 2014, has an interesting feature of separation of concerns in the app. Only the last year I had a chance to have a look at it, when the version 1.0 was released. For all I know it’s being developed actively even know, but it had only 1 pull request in January. I know some developers who use Hanami at work, but at the time of creating the app it was still too crude for us.

Roda

The first stable release was in 2014. It had one pull-request in January.

Should you keep those numbers in mind when you choose a framework? Well, it’s up to you entirely. As for me, they shouldn’t be the key point, but might be useful while you try to choose between several alternatives.

Performance

Performance

You probably know it, but the framework performance is the last thing that may grab your attention. It’s Ruby, you know, the performance is not its strongest point. Even if the project is big, has been on the market for some time and you need to optimize its performance, the web-framework is not your bottleneck here, it’s your code. Or your database queries. Or the wrong architecture.

Personal preferences

As I’ve already mentioned, I’ve been working with Rails and the Rails API for a long time and am ready to work again if needed. However, this time we decided on a different framework. I can recommend you to read a well-known article by Piotr Solnica. But even taking this text and all the advantages of other frameworks into account, if I had to quickly prototype something, my best choice would be Rails.

Sinatra is bare-bones, it has no out of the box features. It works well and causes no problems when it’s customized properly and all neede Gems are added. I had some issues with it at my previous job, but those were mostly my fault. But when you just start using it for your project, you need to do most of the stuff manually, which is rather annoying.

As I’ve already told, I find Hanami fascinating as it allows you to separate concerns inside some particular project and database, as if you were developing microservice architecture, but without any of its difficulties (as well as benefits, of course, as it’s no substation for another). In Hanami there is a shared codebase in lib directory but also apps directory, which may contain several third-party web-interfaces or apps. It seems exciting at first sight, but it’s never a good idea to use the framework you’re not sure about concerning bugs and safety issues, especially if your aim is rapid development. At the time of writing this article, NPM 5.7.0 was released, which has a huge security flaw, which changes the access rights of all your system directories. I’m saying that to note that you never know when the trusted software can do you a bad favor.

Roda. At the moment I was preparing for my presentation at the meetup, I had no practical experience with Roda. Its routing seemed awful to me. Well, my opinion hasn’t really changed since then. Some people at the meetup tried to prove that Roda is the best framework ever existed on the market, so maybe it’s true.

Grape. That’s what we chose in the end. It doesn’t impose its architecture on you, it’s feature-rich, but not too much, not so overloaded with features and has been on the market for quite some time.

A fly in the ointment

There is no ideal framework, they say, so Grape has its bad sides as well. To my mind the first one is that Grape has its own DSL (domain specific language), which means that you should write not common Ruby code, but follow the call and name standards mentioned in Grape docs. Sometimes it leads to remarkably horrible code. See for yourself:

expose :some_attribute, if: ->(element, _) { element.final? } do |element|
  element.my_attribute
end

Conclusion

There’s a word ‘soft’ in ‘software’ for a reason, it is a constantly changing ‘substance’. The requirements to the product itself might change, but also can standards, opinions, preferences and approaches. On top of that, all projects are different and you need to ponder for a while before making up your mind concerning each one. The idea of this article was to show that all Ruby frameworks are diverse, you need to examine and play around with each of them, maybe even try all of them at your project. I hope I was able to do that! And I also recommend you to have Grape in mind, it’s a wonderful API framework!

Do you want to know more about Ruby and APIs? You can start with reading article series in which Kirill Shirinkin creates a Gem for working with an external API from scratch Development of GrooveHQ Ruby Gem.

Cookies help us deliver our services. By using our services, you agree to our use of cookies.