Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multipart request support #65

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

pucinsk
Copy link

@pucinsk pucinsk commented Oct 31, 2019

This PR allows send files via graphql. It adds FaradayMultipartAdapter to allow send multipart requests via graphlient gem.
It accepts File instances and convert its to Faraday::UploadIO before sending.

@dangerpr-bot
Copy link

dangerpr-bot commented Oct 31, 2019

1 Warning
⚠️ Unless you’re refactoring existing code, please update CHANGELOG.md.

Here's an example of a CHANGELOG.md entry:

* [#65](https://github.com/ashkan18/graphlient/pull/65): Add multipart request support - [@pucinsk](https://github.com/pucinsk).

Generated by 🚫 Danger

Copy link
Collaborator

@dblock dblock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty cool, but it seems strange to me that you would have to use a different adapter to send a file. Shouldn't I be able to do that by default?

README.md Outdated Show resolved Hide resolved
@@ -17,4 +17,5 @@ Gem::Specification.new do |s|
s.add_dependency 'faraday'
s.add_dependency 'faraday_middleware'
s.add_dependency 'graphql-client'
s.add_dependency 'mime-types'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gems related to mime types are known to allocate excessive memory. Have you looked into the mini_mime gem?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I haven't thought about it.
Yup, mini_mime should work as expected too.

And what do you think if we try to load mime types lib from users environment and if he does not have any mime types library then we throw an expection and enforce user to install mime types lib with a message_No mime types library detected you must add to your Gemfile mime-types or mini_mime gem_?
Code could look something like that:

def mime_type(file)
  if defined?(MIME::TYPES) 
    MIME::TYPES.type_for(file.path)
  if defined?(MiniMyme)
     MiniMyme.lookup_by_filename(file.path)
  else
    raise Graphlient::Errors::NoMimeTypesLibError, 'Please add `mime-types` or `mini_mime` gem to your Gemfile'
  end
end

It would nice for Rails users because Rails already includes mime-types gem.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a good idea 👍


response.body
rescue Faraday::ClientError => e
raise Graphlient::Errors::FaradayServerError, e
Copy link
Collaborator

@yuki24 yuki24 Oct 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem right to translate client errors to server errors. Also, you don't have to pass in the e to the second argument as Ruby captures the cause and users have access to it with exception#cause.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, it was shamefully copy-pasted from FaradayAdapter
So I cannot tell why it does looks so.

let(:variables) { { val: { file: File.new('spec/support/fixtures/empty.txt') } } }

it 'contverts file to Faraday::UploadIO' do
expect(call[:val][:file]).to be_a(Faraday::UploadIO)
Copy link
Collaborator

@yuki24 yuki24 Oct 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Ruby, duck typing is more preferable rather than checking classes.

Copy link
Owner

@ashkan18 ashkan18 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this and also adding specs! Looks awesome! 😍

Just have the same question as @dblock about possibly not needing a separate adapter for this and have Faraday middleware handling this. I wonder if its sufficient to just set proper header for multipart requests and have Faraday handle it automatically.


def file_variable_value(file)
content_type = MIME::Types.type_for(file.path).first
return Faraday::UploadIO.new(file.path, content_type) if content_type
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we use Faraday::FilePart or Faraday::ParamPart based on this doc?

Copy link
Author

@pucinsk pucinsk Nov 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mhm. Good point. Faraday::UploadIO will be deprecated. 😞 But in Faraday v0.17.0 UploadIO is only valid way to add files to request.
I think the next Faraday version will v1.0 and it will have Faraday::Parts module where all parts of request will be described.
Maybe we should specify faraday gem version in Gemfile just to make sure that for now Faraday::UploadIO could work?

@dblock
Copy link
Collaborator

dblock commented Nov 6, 2019

@pucinsk My biggest reservation about this PR is the creation of another adapter. Can we build multipart support into the existing one? What's the downside?

@pucinsk
Copy link
Author

pucinsk commented Nov 7, 2019

There are no downsides. I thought that it could be optional adapter.
But if it would be better that files supporting would be enabled by default than I am more than willing to add this to main FaradayAdapter

@ashkan18
Copy link
Owner

ashkan18 commented Nov 7, 2019

Thanks @pucinsk, yes that would be awesome to add support to existing adapter. Thanks so much!

@dblock
Copy link
Collaborator

dblock commented Nov 7, 2019

Yes, 1 adapter > 2 adapters.

@uiltonlopes
Copy link

Hi can you merge the branch? I would like to use this functionality

Copy link
Collaborator

@dblock dblock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see above. From the user POV a separate adapter is too difficult to use, as it requires creating a separate client to upload files from other requests. The ask is to integrate support for multipart requests into the existing one. Happy to merge something along those lines.

@uiltonlopes
Copy link

This is pretty cool, but it seems strange to me that you would have to use a different adapter to send a file. Shouldn't I be able to do that by default?

Alright master. Can you help me with some file upload example that still manages to leverage the gem

@dblock
Copy link
Collaborator

dblock commented Jul 23, 2022

This is pretty cool, but it seems strange to me that you would have to use a different adapter to send a file. Shouldn't I be able to do that by default?

Alright master. Can you help me with some file upload example that still manages to leverage the gem

I've never done that myself, so don't know how to do it with the current implementation. If you want to try and refactor this PR to support multipart I can try to help out fix any remaining issues on something that (almost) works.

@PedroAugustoRamalhoDuarte

Hello guys, is there any way to send files with Graphlient, or only with this PR?

@dblock
Copy link
Collaborator

dblock commented Dec 22, 2023

I don't know of one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants