Search code examples
httpelixirslackslack-api

Can't upload pdf to slack "no_file_data" with Elixir and Hackney


I'm writing a slack bot in Elixir that has to upload a pdf to a channel.

Here's what I've come up with:

    {:ok, ref} = :hackney.request(
      :post,
      "https://slack.com/api/files.upload?"
      <> Plug.Conn.Query.encode(%{
          "channels" => channel_id,
          "filename" => "test.pdf",
          "filetype" => "pdf"
        }),
      [
        {"Content-Type", "multipart/form-data"},
        {"Authorization", "Bearer xoxb-XXXXX"},
      ],
      :stream_multipart,
      [])

    :hackney.send_multipart_body(
      ref,
      {:file, "./test.pdf"})

    {:ok, _status, _headers, ref} = :hackney.start_response(ref)

    {:ok, body} = :hackney.body(ref)

    body |> Poison.decode! |> IO.inspect

But I get this error: %{"error" => "no_file_data", "ok" => false}

I've used this question as a basis: Streaming a file using hackney

Version:

  • Elixir: 1.10.2
  • OTP: 22.0.7
  • Hackney: 1.15
  • PLug: 1.10

Solution

  • Problem solved. I Just needed to remove {"Content-Type", "multipart/form-data"} in the header of the request. Hackney already provides one with a boundary.

    My Content-Type Looked like this:

    Content-Type: multipart/form-data
    

    When it should have looked like this:

    Content-Type: multipart/form-data; boundary=---------------------------tlzhgtmgeelwolfm
    

    Here is the corrected code:

        {:ok, ref} = :hackney.request(
          :post,
          "https://slack.com/api/files.upload?"
          <> Plug.Conn.Query.encode(%{
              "channels" => channel_id,
              "filename" => "test.pdf",
              "filetype" => "pdf"
            }),
          [
            {"Authorization", "Bearer xoxb-XXXXX"},
          ],
          :stream_multipart,
          [])
    
        :hackney.send_multipart_body(
          ref,
          {:file, "./test.pdf"})
    
        {:ok, _status, _headers, ref} = :hackney.start_response(ref)
    
        {:ok, body} = :hackney.body(ref)
    
        body |> Poison.decode! |> IO.inspect