adding params in faraday middleware

2.4k views Asked by At

I am trying to write a middleware that will set additional params to the query string. The use case is to be able to add additional authentication tokens, for eg, to the request as required by the backend, but wanting to inject it independent of the request creation itself.

This is what my middleware(pseudo code) looks like:

class MyMiddleware < Struct.new(:app, :key, :value) 
  def call(env)
    env.params[key] = value #1
    #env.params = {key => value} #2
    app.call env
  end
end
  1. above raises NoMethodError (undefined method[]=' for nil:NilClass)`
  2. above sets the params hash but the parameter is not encoded as part of the query string. The query string remains what it was before the middlewares start processing the request.

My analysis is that since the query string gets built from the params in rack_builder.rb:191

def build_response(connection, request)
  app.call(build_env(connection, request))
end

def build_env(connection, request)
  Env.new(request.method, request.body,
    connection.build_exclusive_url(request.path, request.params), #<== rack_builder.rb:191
    request.options, request.headers, connection.ssl,
    connection.parallel_manager)
end

Middlewares don't get the opportunity to set additional params. While env has a params property, it is nil and doesn't appear to be touched during or after the middlewares get invoked.

So, I have the following questions: 1. Is there a supported way to achieve this? 2. If not, is there a way to rebuild the query string as part of the middleware executing? 3. Would it be better to defer the URL building to after most of the request middleware chain is executed (but of course, before the adapter gets to do its thing; or do it in the adapter)? 4. Any other options?

Appreciate any guidance.

1

There are 1 answers

0
abookyun On

The answer is here at github: https://github.com/lostisland/faraday/issues/483 by @mislav

Inside the middleware, the request URL is already fully constructed together with all the configured query parameters in a string. The only way to add or remove query parameters is to edit the env.url.query string, e.g.:

MyMiddleware = Struct.new(:app, :token) do
  def call(env)
    env.url.query = add_query_param(env.url.query, "token", token)
    app.call env
  end

  def add_query_param(query, key, value)
    query = query.to_s
    query << "&" unless query.empty?
    query << "#{Faraday::Utils.escape key}=#{Faraday::Utils.escape value}"
  end
end

conn = Faraday.new "http://example.com" do |f|
  f.use MyMiddleware, "MYTOKEN"
  f.adapter :net_http
end

However, if your middleware is going to be like MyMiddleware above and just add a static query parameter to all requests, the much simpler approach is to avoid the middleware and just configure the Faraday connection instance to apply the same query parameter to all requests:

conn = Faraday.new "http://example.com" do |f|
  f.params[:token] = "MYTOKEN"
  f.adapter :net_http
end