October 15, 2025
 — Upgrades 

Migrating from rest-client to faraday

Zac Radford
Software Engineer

One of the components of dependency management that can sometimes be less than straightforward is removing dependencies that are no longer maintained, or abandoned. At Infield we try to assess the “abandonedness” of a dependency based on a few different criteria, like release cadence and Github chatter asking whether this package is being maintained. Recently, while I was removing and replacing the rest-client gem I ran into a feature that isn’t present in its most common replacement.

First, rest-client 2.1.0 was released in 2019, and has been in maintenance mode, receiving only minor changes in the last 6 years. It's a prime candidate for being replaced with something that receives active support, like faraday. Faraday has a helpful guide in their docs to help with this exact migration, which is very handy, but it of course can't cover everything. One convenient pattern from rest-client that didn't have a direct Faraday replacement for in their guide was the ability to use [] to construct sub-resources to arbitrary depth:

   site = RestClient::Resource.new('http://example.com')

       # => #<RestClient::Resource @url="http://example.com">

   posts = site['posts']

       # => #<RestClient::Resource @url="http://example.com/posts">

   first_post = posts['1']

       # => #<RestClient::Resource @url="http://example.com/posts/1">

   comments = first_post['comments']

       # => #<RestClient::Resource @url="http://example.com/posts/1/comments">

This opens up a pattern where you can store your root url into a constant or method that can be built on top of because [] returns another RestClient::Resource object, with the new path tacked on:

RESOURCE = RestClient::Resource.new('http://example.com')

def create_record_resource

 RESOURCE['record/create.json']

end

Those resources are then used in equally simple method calls:

def create_record(phone_number)

 create_record_resource.post(default_params.merge(id: @record.id, phone_number:))

end

This usage of [] isn't built-in to Faraday, so changes have to be made. I started by converting the methods that called RESOURCE['some/path'] into methods that just returned the path. Then, I could easily move those methods into the calls to post and put like so:

def create_record_path = 'record/create.json'

def create_record(phone_number)

 RESOURCE.post(create_record_path, default_params.merge(id: @record.id, phone_number:))

end

Take reducing duplication one step further you can use metaprogramming to write RESOURCE and merge default_params in one place:

%i[ post put ].each do |verb|

 define_method(verb) do |url, **body|

   RESOURCE.send(verb, url, default_params.merge(body))

 end

end

This bit of ruby magic lets us preserve the simplicity of rest-client's [], with the security of an actively maintained gem like faraday:

def create_record(phone_number)

 post create_record_resource, id: @record.id, phone_number:

end