Faraday Connection: Switching the request mode?
Asked Answered
H

3

6

I am using faraday to handle some requests to an internal API. The API endpoints use a CSRF token, so I am also using faraday-cookie_jar.

For a couple of the API endpoints, they require a :multipart request. Others do not.

Question

Is there any way to utilize the same Connection object, but switch whether or not you are doing a :multipart or a :url_encoded request?

Currently, I have to use two connections depending on which type of request I'm making. It does not seem you can change a connection's request method after it has done at least 1 request.

@connection = Faraday.new(url: 'http://localhost:3000') do |faraday|
  faraday.request :url_encoded
  faraday.use :cookie_jar
  faraday.adapter Faraday.default_adapter
end

@connection.get '/something'

# try to change to :multipart
@connection.request :multipart # => Faraday::RackBuilder::StackLocked: can't modify middleware stack after making a request

It doesn't seem to allow you to switch after you've made a request. I know that you can modify the request a bit for each request itself by passing a block, but I can't seem to find where to modify to switch to :multipart in it.

Thanks in advance.

Harry answered 2/3, 2016 at 3:37 Comment(0)
M
2

You'll want to include both middleware options when creating your connection (:url_encoded and :multipart), and then switch using explicit Content-Type headers.

Per the Faraday ReadMe, you can specify 'em both. An excerpt:

 Faraday.new(...) do |conn|
    # POST/PUT params encoders:
    conn.request :multipart
    conn.request :url_encoded
    conn.adapter :net_http
  end

This request middleware setup affects POST/PUT requests in the following way:

  1. Request::Multipart checks for files in the payload, otherwise leaves everything untouched;
  2. Request::UrlEncoded encodes as "application/x-www-form-urlencoded" if not already encoded or of another type.

So adding :multipart still allows for url-encoded posts, because it only matters when there are files in the payload. Then, if you explicitly set your Content-Type for the file upload, you should be fine - Faraday will use the correct request middleware because you explicitly told it to use multipart. But if you don't specify, it will default to url-encoded.

# works using :url_encoded
@connection.post '/something' do |req|
  req.body = { some: 'posted fields' }
end

# works using :multipart because Content-Type was explicitly set
@connection.post '/some_file_endpoint' do |req|
  req.headers['Content-Type'] = 'multipart/form-data'
  req.body = { file_field: Faraday::UploadIO.new(file_path, 'text/plain') }
end
Much answered 1/4, 2016 at 23:13 Comment(0)
L
0

Calling @connection.request :multipart adds Faraday::Request::Multipart to @connecton.builder.handlers. If you want to remove something, you can manipulate that array.

I make no claim that messing with Faraday's (relative) internals is a good idea. Keeping your two connections sounds like a better plan.

Lunchroom answered 5/3, 2016 at 11:19 Comment(0)
D
0

Sean’s answer sounds like the right thing to do here, but if you do want to modify your connection, you have to duplicate it before:

@connection = @connection.dup
@connection.request :multipart

This can also be used to delete middleware from a connection:

@connection = @connection.dup
@connection.builder.delete(Faraday::Request::lookup_middleware(:multipart))
Deception answered 26/1, 2022 at 14:31 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.