How to Write a Faraday Request Middleware
Faraday is a very powerful tool, and you can make it even more powerful.
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 MyLogger
def info(text_to_log)
puts text_to_log
end
end
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 FaradayMiddleware
class LogRequests < Faraday::Middleware
def initialize(app, logger)
super(app) @app = app
@logger = logger
end def 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)
end
end
end
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 ./request
file_path = "#{File.dirname(__FILE__)}/request/log_requests.rb"
autoload :LogRequests, file_path # register the middleware under the key :log_requests, for later
# use
Faraday::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 faraday
require 'faraday'# we need our logger
require_relative 'lib/my_logger'# we need our middleware
require_relative 'lib/faraday_middleware/log_requests'# create an instance of our logger to pass into our middleware
logger = MyLogger.new# create a new Faraday connection interface
connection = Faraday.new(url: 'https://brandoncc.dev') do |conn|
# use our middleware
conn.request :log_requests, logger
endconnection.get('/')
and use it:
$ ruby example_usage.rb
Using 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!
Brandon Conway
I enjoy learning about and writing code in many programming languages
Originally published at https://brandoncc.dev.