How to Write a Faraday Request Middleware
May 31, 2020
TL;DR
Check out the repo to see the files we create in this blog post.
Welcome
Faraday is a Ruby web request library.
Ruby’s standard library includes tools such as Net::HTTP
to make requests, but
using them can be a little unwieldy, especially when it comes to handling
errors. Faraday abstracts all of that away, giving you a nice interface.
I recently needed to add the ability to cache the last request I made, so that I could send it to Rollbar if it failed. I had to dig through the source code, as well as implementations such as this one and this one in order to figure out how to write middleware.
My goal with this blog post is to help you understand how to write a request
middleware of your own. Response middleware should use most of the same code,
but they require use of the #on_complete
method access to the response in a safe
way.
I highly recommend taking a look at the Faraday Middleware Docs to get an idea what middleware can do for you, and what it is.
Setup
The first thing you will need is your actual middleware file. This consists of a
class which can be instantiated during the request. The class will receive the
Faraday state (colloquially known as app
) as its first instantiation argument,
and any arguments you give when utilizing your middleware as subsequent
arguments.
There are only two things you need to do in order to satisfy Faraday:
- Call
#super
withapp
in#initialize
. - Add a
#call
method, which is where the middleware does its processing. You need to callapp.call
with the environment, which is provided to the#call
method as an argument.
I realize #2 is probably a little confusing, but you can see it in action in
lib/faraday_middleware/request/log_requests.rb
below.
Building Our Middleware
We will be building a basic request logger together.
The MyLogger Class
The first thing we need is a logger. You could use any logger for this, but for simplicity, we will create a very basic one:
lib/my_logger.rb
# frozen_string_literal: trueclass MyLoggerdef info(text_to_log)puts text_to_logendend
The Faraday Middleware
What would a middleware be without a middleware class? We’ll create that next:
The middleware will accept the Faraday state as the first argument, then a
logger as a second argument. We will store both of those for use in the #call
method.
lib/faraday_middleware/request/log_requests.rb
# frozen_string_literal: truemodule FaradayMiddlewareclass LogRequests < Faraday::Middlewaredef initialize(app, logger)super(app)@app = app@logger = loggerenddef call(env)# any processing you want, including altering the environment# (see https://lostisland.github.io/faraday/middleware/custom)@logger.info("Using method #{env.method} to access #{env.url}")# You must do this when you are done with your processing@app.call(env)endendend
The Middleware loader
Before we can use a Faraday middleware, we need to register it with Faraday.
We’re going to use the Kernel#autoload
method so that our middleware is not
loaded until it is actually used. This is the convention given by Faraday
themselves, in the middleware that they offer and
maintain.
lib/faraday_middleware/log_requests.rb
# frozen_string_literal: truerequire 'faraday'module FaradayMiddleware# load the middleware from the relative directory ./requestautoload :LogRequests, "#{File.dirname(__FILE__)}/request/log_requests.rb"# register the middleware under the key :log_requests, for later useFaraday::Request.register_middleware log_requests: -> { LogRequests }end
Using Our Middleware
The only thing left to do is actually use our middleware!
Let’s create a basic script that will make a web request
example_usage.rb
# frozen_string_literal: true# we need faradayrequire 'faraday'# we need our loggerrequire_relative 'lib/my_logger'# we need our middlewarerequire_relative 'lib/faraday_middleware/log_requests'# create an instance of our logger to pass into our middlewarelogger = MyLogger.new# create a new Faraday connection interfaceconnection = Faraday.new(url: 'https://brandoncc.dev') do |conn|# use our middlewareconn.request :log_requests, loggerendconnection.get('/')
and use it:
$ ruby example_usage.rbUsing method get to access https://brandoncc.dev/
That’s it! In a few minutes, we were able to tap into the request cycle and add some logic that we needed. I hope I have successfully shown you how valuable middleware can be, and how to use it with Faraday to improve your scripts and applications.
I highly recommend checking out the middleware offered by the Faraday team, because you might find what you are looking for already exists.
Thank You, Friend
Thanks for spending some of your valuable time reading my blog post, and I hope to see you again!