Upload image failed use HTTP::Client but test with postman work

Okay, I spent some time looking into this and there are a few things going on:

  1. Are mixing application/x-www-form-urlencoded and multipart/form-data content types
  2. In the latter case, not including the boundary in the header

When you pass something to the form property, it internally overrides your Content-Type header to application/x-www-form-urlencoded, yet the body of the request is multipart/form-data. You can reproduce this in Postman too by unchecking the default Content-Type header and adding a custom one with application/x-www-form-urlencoded.

Ultimately the fix is to settle on one or the other:

# application/x-www-form-urlencoded
response = HTTP::Client.post(
  url: "https://freeimage.host/api/1/upload",
  form: {
    "key"    => "my_key",
    "source" => "https://avatars.githubusercontent.com/u/549126?s=96&v=4",
  }
)

However, because you said you’re going to be uploading files, will likely want to use multipart/form-data. Which you’d want to handle by just passing it as the body. E.g. body: io.rewind. But there is still one thing missing. The content-type headers needs the boundary for multipart requests. Which you can get from the HTTP::FormData::Builder instance:

io = IO::Memory.new

form_data = HTTP::FormData::Builder.new(io)
form_data.field("key", "my_key")
form_data.field("source", "https://avatars.githubusercontent.com/u/549126?s=96&v=4")
form_data.finish

response = HTTP::Client.post(
  url: "https://freeimage.host/api/1/upload",
  headers: HTTP::Headers{"content-type" => form_data.content_type},
  body: io.rewind
)
1 Like