How to convert this CURL request with a -F param to a Req request?

This CURL request works fine:

curl -X POST \
-H "Ocp-Apim-Subscription-Key: 123123123123123" \
-F "knowledgeRequest={\"imageInfo\":{\"url\":\"https://i.ebayimg.com/images/g/Mn8AAOSwoLtgZ2au/s-l1600.webp\"}}" \
"https://api.bing.microsoft.com/v7.0/images/visualsearch?mkt=en-us"

And here’s what I’ve tried to run this in Elixir using Req:

url = "https://api.bing.microsoft.com/v7.0/images/visualsearch?mkt=en-us"
api_key = System.get_env("MICROSOFT_OCP_APIM_SUBSCRIPTION_KEY")

headers = [
  {"Ocp-Apim-Subscription-Key", api_key}
]

# Doesn't work.
knowledge_request = "{\"imageInfo\":{\"url\":\"#{image_url}\"}}"

# Doesn't work.
knowledge_request =
  %{
    imageInfo: %{
      url: image_url
    }
  }
  |> Jason.encode!()

case Req.post(url, headers: headers, form: [knowledgeRequest: knowledge_request]) do
  {:ok, response} ->
    response

  {:error, reason} ->
    {:error, reason}
end

Error comes back as:

** (ArgumentError) errors were found at the given arguments:

  • 1st argument: not an iodata term

    :erlang.iolist_to_binary(%{“_type” => “ErrorResponse”, “errors” => [%{“code” => “InvalidRequest”, “message” => “Parameter has invalid value.”, “moreDetails” => “Parameter has invalid value.”, “parameter” => “knowledgeRequest”, “subCode” => “ParameterInvalidValue”}], “instrumentation” => %{“_type” => “ResponseInstrumentation”}})
    (jason 1.4.4) lib/jason.ex:69: Jason.decode/2
    (shopnik 0.1.0) lib/shopnik/bing_image_search.ex:22: Shopnik.BingImageSearch.parse_response/1
    iex:12: (file)

Appreciate any tips!

This works with HTTPoison.

 knowledge_request =
  Jason.encode!(%{
    imageInfo: %{
      url: image_url
    }
  })

 body =
  {:multipart,
   [
      {"knowledgeRequest", knowledge_request, {"form-data", [{"name", "knowledgeRequest"}]},
      []}
   ]}

case HTTPoison.post(url, body, headers) do

Check this library out: CurlReq — CurlReq v0.98.5

The author says it can convert in both directions.

3 Likes

I don’t think you have to encode it as JSON and just pass in the map. Following the docs at Req.Steps — req v0.5.4

But CurlReq should also give you the correct answer, if not, please open an issue in the GitHub repo

form sets application/x-www-form-urlencoded, I believe you want multipart/form-data which is available in recent Req releases using :form_multipart. Something like this should work:

Req.post(url, headers: headers, form_multipart: [knowledgeRequest: knowledge_request])

Please let me know and/or open an issue otherwise!

2 Likes