« 25 Days of Ruby Gems - Ruby Advent Calendar 2020, December 1st - December 25th

Day 20 - lhs and lhc Gems - Easy Active Record-Like Interfaces for Accessing HTTP JSON APIs - Smarter Higher-Level HTTP Service and Lower-Level HTTP Client

Written by marcoroth Marco Roth

Full-Stack Web-Developer based in Basel, Switzerland. Building stuff with Ruby, Rails, Stimulus and JavaScript. StimulusReflex core team member.


I love Ruby and I think Ruby solved a lot of things elegantly with a ton of features directly built into the standard library. HTTP requests in Ruby with net/http are the only thing that never really clicked for me. In fact net/http has been there forever, but im my experience it never was a blast to work with.

In 2019 I attended a local Ruby Meetup and heard a talk by spape Sebastian Pape about “Smart HTTP Clients”. In that talk Sebastian talked about how they were building HTTP Clients at localsearch.ch and how their HTTP clients evolved over the years and what kind of issues and pains they were facing.

He showed off the two libraries lhs and lhc which they’ve built over the years in order solve the issues they experienced with the mapping between Ruby objects and JSON responses from HTTP APIs.

Entering lhs and lhc.

What is lhs and lhc?


LHC (“Localsearch.ch HTTP Client”) is an advanced HTTP client which builds on top of the fast typhoeus gem for low level http communication.

It supports a wide range of enhancements like interceptors, exception handling, format handling, accessing response data, configuring endpoints/placeholders and fully compatible, RFC-compliant URL-template support.


LHS (“Localsearch.ch HTTP Service”) is a higher-level gem built on top of the lower-level LHC. It provides an easy and Active Record-like interface for accessing HTTP JSON APIs / web services.

It offers a lot of features that makes you think that you don’t even interact with a remote HTTP JSON API-endpoint anymore! It feels like you interact with the database directly.

Setup and examples

Without further ado let’s jump into some spicy examples.


The intuitive and straight-forward interface of LHC makes it really easy to execute HTTP requests. After adding the lhc gem to your project you can request JSON endpoints like this:

feedbacks = LHC.get('https://datastore.com/v1/feedbacks')


You can easily access the JSON data provided in the response and access all the related informations of the response. LHC also works with any other kind of HTTP requests. I just showcase the built-in JSON support here.

There is a similar method for all the HTTP-methods. Here’s an example of a simple POST request:

LHC.json.post('https://datastore.com/v1/feedbacks', body: { name: 'Hello', recommended: true })

While I just want to cover the basic use here there is a lot more features to discover! The gem is really feature loaded. You should checkout the detailed README.


Let’s talk about LHS. I was excited the first time I saw LHS in action. In order to demonstrate what LHS offers: Let’s build a simple Active Record-like wrapper for the request we did in the LHC example above to show off it’s capabilities.

After adding the lhs gem to your project you can configure the LHC-Client which LHS is going to use. This example uses Rails, but LHS also works fine outside of Rails (for example if you want to create an API-wrapper gem).

Let’s define the root URL for our service (this is helpful if you have different environments):

# config/initializers/lhc.rb

LHC.configure do |config|
  config.placeholder(:service, 'https://datastore.com/v1')

With that we can create our first record:

# app/models/feedback.rb

class Feedback < LHS::Record
  endpoint '{+service}/feedbacks'
  endpoint '{+service}/feedbacks/{id}'

If you believe it or not: with that we just built a simple Active Record-like wrapper for our API! It lets us fetch, create, update and delete records plus lots more.

Of course this doesn’t use any authentication yet, but this will be easy to add later on.

This allows us now to query the API as such:

feedback = Feedback.find(3424)

# => true

You can also use all the methods you know and love from Active Record:

Feedback.find(1, 2, 3)
Feedback.find_by(user_id: 45352)
Feedback.first(params: { recommended: true })
Feedback.where(recommended: true)

It’s easy to build, create, update and delete records:

Feedback.create(text: 'Hello world')
# POST https://datastore.com/v1/feedbacks

feedback = Feedback.new
feedback.text = 'Hello world'
feedback.recommended = true
# POST https://datastore.com/v1/feedbacks

feedback = Feedback.find(3424)
feedback.update(recommended: true)
# PATCH https://datastore.com/v1/feedbacks/3424

# DELETE https://datastore.com/v1/feedbacks/3424

I think this is awesome! You can create API wrappers with that in no time.

With that said, it’s a powerful and easy to use gem. There is a whole lot more to discover, which I can’t cover in this showcase here.

Here is a list of more awesome features LHS provides:

Why and where should I use lhs and lhc?

The next time you have to built against a remote HTTP JSON API or have the need for a nice but simple and powerful HTTP client think about if LHS or LHC fits for your use case.

LHC is currently my preferred HTTP client and is included in almost every new project I start. If you need a simple, easy-to-use and advanced HTTP client, LHC is a proper fit!

The same applies for LHS. Whether you are going to …

… I think you aren’t going to be disappointed!

Give it a shot, star the projects on GitHub and tell me about your experiences!

What’s next?

I encourage you to checkout the awesome, detailed and thought-through READMEs the localsearch.ch team have put together. They contain both simple and advanced examples of how you can use the gems. They even give you the feeling that they thought about every little detail you didn’t even know you needed!


To be fully transparent: There are numerous other gems providing the same or similar functionalities. Choose whatever fits your use case best. I’ve been really happy with the easiness and intuitiveness of LHC and LHS. In the end it really depends on your use case and your preferences.

I’ll list the alternatives that I’ve came across in alphabetical order:

Wrapping up

To be honest it has been a blast to work with those gems. I’ve really learned to love and appreciate the two gems!

I’d like to thank you for reading this showcase! Hit me up on Twitter if you got any questions about LHC or LHS.

A special thanks goes out to spape Sebastian Pape and the team for providing such beautiful and well documented gems! Thank you!


Find Out More



Built with Ruby (running Jekyll) on 2021-03-12 22:04:06 +0000 in 0.371 seconds.
Hosted on GitHub Pages. </> Source on GitHub. (0) Dedicated to the public domain.