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

Testing with file uploads #1145

Open
jwoertink opened this issue May 17, 2020 · 0 comments
Open

Testing with file uploads #1145

jwoertink opened this issue May 17, 2020 · 0 comments
Labels
hacktoberfest Valid Issue for Hacktoberfest

Comments

@jwoertink
Copy link
Member

Right now we don't really have a way to do this. If your action requires a file to be uploaded, you'll have to handroll the whole deal.

Here's a spec that shows how to do this:

# src/actions/home/index.cr
class Home::Index < ApiAction
  post "/" do
    data = params.get_file?("file").try { |f| File.read(f.path) }.to_s
    json({hello: data})
  end
end
# spec/actions/home/index_spec.cr
require "../../spec_helper"

describe Home::Index do
  it "sends a file" do
    text = IO::Memory.new
    channel = Channel(String).new(1)

    spawn do
      HTTP::FormData.build(text) do |formdata|
        channel.send(formdata.content_type)

        formdata.field("name", "text")
        File.open("spec/test.txt") do |file|
          metadata = HTTP::FormData::FileMetadata.new(filename: "test.txt")
          headers = HTTP::Headers{"Content-Type" => "plain/text"}
          formdata.file("file", file, metadata, headers)
        end
      end
    end

    headers = HTTP::Headers{"Content-Type" => channel.receive}
    response = HTTP::Client.post(Home::Index.url, body: text.rewind, headers: headers)
    response.should send_json(200, hello: "testing")
  end
end

Issues

  • The params.get_file method will return a Lucky::UploadedFile; however, because the tempfile is created using a block, the file is actually closed. This means that you can't read the file without reopening it (e.g. params.get_file(:file).tempfile.gets_to_end throws a Closed stream error). We should add a method to this class that calls File.read(tempfile.path) as a convenient way to get the contents of a file.
  • The Content-Type has to be the whole multipart form data for the HTTP::Server to parse it properly. The AppClient sets this to application/json by default. You don't know what the content type will be until you start building HTTP::FormData and ask for its content_type. In the example above, a channel is used to grab the value and send it later.
  • I'm not using AppClient in this example, because the exec method will call to_json which fails with a no method overload for IO#to_json.
  • No other params are being passed in this example because I couldn't figure it out. Putting the data in to any other format seemed to throw MultiPart errors.

Solutions

  • We call File.read(), then Base64 that string, and send it over. The downside here is Base64 increases the string size by up to 33% (from what I've read), and this no longer gives us access to params.get_file? because it's not a file, it's a string...
  • We could add another exec overload where the user passes in their params, and we take that, then iterate over it adding it in to the formdata. This would give you access to those params through params.get(:whatver) like normal.

I'm sure there's other solutions, but I don't have many ideas.

@jwoertink jwoertink added the hacktoberfest Valid Issue for Hacktoberfest label Oct 1, 2021
@jwoertink jwoertink removed the hacktoberfest Valid Issue for Hacktoberfest label Nov 1, 2021
@jwoertink jwoertink added the hacktoberfest Valid Issue for Hacktoberfest label Oct 1, 2022
@jwoertink jwoertink removed the hacktoberfest Valid Issue for Hacktoberfest label Nov 6, 2022
@jwoertink jwoertink added the hacktoberfest Valid Issue for Hacktoberfest label Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hacktoberfest Valid Issue for Hacktoberfest
Projects
None yet
Development

No branches or pull requests

1 participant