0

In my Rails 7 app third party API require to send the PDF file created by my application. I've got sample curl from the API docs:

curl -X POST --header 'Content-Type: multipart/form-data' --header 'Accept: application/json' {"type":"formData"} 'https://some_path.com'

I'm using Faraday gem with below implementation of client and resource:

# app/clients/test_api/client.rb
module TestApi
  class Client
    include ::Errors

    API_ENDPOINT = 'https://some_path.com'
    ACCESS_TOKEN = Rails.application.credentials.api_token

    def initialize
      @access_token = ACCESS_TOKEN
    end

    def post(path, options = {})
      handle_response(client.public_send(:post, path.to_s, options.to_json))
    end

    attr_reader :access_token

    private

    def client
      @client =
        Faraday.new(API_ENDPOINT) do |client|
          client.request :url_encoded
          client.response :json, content_type: /\bjson$/
          client.adapter Faraday.default_adapter
          client.headers['Accept'] = 'application/json'
          client.headers['Content-Type'] = 'application/json'
          client.headers['apiToken'] = access_token.to_s if access_token.present?
        end
    end

    def handle_response(response)
      return response_body(response) if response.success?

      raise error_class(response.status)
    end

    def response_body(response)
      response&.body
    end
  end
end

# app/clients/test_api/resources.rb
module TestApi
  class Resources
    def upload_document(file)
      client.post('/sspfile/uploadtemporary', body: file)
    end

    private

    def client
      @client ||= Client.new
    end
  end
end

But how to send the file as a body params? I've got the API error with my implementation so seems like it's not that simple.

tajfun_88
  • 41
  • 6

1 Answers1

1

You have to use Faraday::UploadIO class to first create an UploadIO object and pass that into the request.

Make changes in these lines of your code:

# app/clients/test_api/client.rb
module TestApi
  class Client
    ...

    def post(path, options = {})
      handle_response(client.public_send(:post, path.to_s, options.to_json))
    end

    ...
  end
end

# app/clients/test_api/resources.rb
module TestApi
  class Resources
    def upload_document(file)
      uploaded = Faraday::UploadIO.new(file, 'application/pdf')
      client.post('/sspfile/uploadtemporary', file: uploaded)
    end

    ...
  end
end

Can read here for more info on UploadIO class: https://rubydoc.info/gems/multipart-post/1.1.0/UploadIO

rkwap
  • 136
  • 2
  • 5
  • This code generates below error: `send_request_with_body: undefined method bytesize' self.content_length = body.bytesize` – tajfun_88 Dec 12 '22 at 17:11
  • try sending options as json string instead of hash. like this: ```handle_response(client.public_send(:post, path.to_s, options.to_json))``` Also, updated in the answer – rkwap Dec 16 '22 at 18:00
  • Absolutely no difference. – tajfun_88 Dec 20 '22 at 22:15