Harrygr

Harrygr

File upload mutation with Abinthe giving "no query document supplied" error

I’m trying to build an upload component to allow uploading of files over graphql. I’m using Absinthe for the server aspect and React + URQL (along with the multipart fetch exchange) for the frontend. I’ve followed the file uploads section of the Absinthe docs and I have it working via curl as follows:

curl -v -X POST -F query="mutation { uploadFile(input: {file: \"myfile\"}) { result }}" -F myfile=@avatar.png localhost:4000/graphql

However I can’t seem to get this same mutation to work when using URQL. The server just responds with a “no query document supplied” error.

Here’s an example of the multipart request from the browser:

-----------------------------283482549016739198714264561499
Content-Disposition: form-data; name="operations"

{"variables":{"input":{"file":null}},"query":"mutation UploadFile($input: UploadFileInput!) {\n  uploadFile(input: $input) {\n    result\n    __typename\n  }\n}\n"}
-----------------------------283482549016739198714264561499
Content-Disposition: form-data; name="map"

{"1":["variables.input.file"]}
-----------------------------283482549016739198714264561499
Content-Disposition: form-data; name="1"; filename="avatar.png"
Content-Type: image/png

‰PNG
 <rest of image data

Could there be a discrepency between implementations?

First Post!

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Yes, URQL is using a different pattern for file uploads. I’ve been fighting this spec forever because I hate the use of null as a marker for a value that is not null. However it seems this spec is getting popular and this is a fight I’m going to lose eventually. sigh.

Most Liked

sb8244

sb8244

Author of Real-Time Phoenix

I found this thread when googling. I didn’t want to rewrite anything on the client because that sounds pretty rough, so I went for the Elixir rewriting approach. I hooked into multipart_to_params, an option to the Plug.Parsers plug that’s usually put in Endpoint

This code works for my simple case locally. I didn’t test with multiple files because that’s not a use case for me. I also didn’t worry about graceful params handling. Use at own risk, but possibly a decent starting point:

defmodule RewriteMultipart do
  def multipart_params(parts, conn) do
    params =
      for {name, _headers, body} <- parts,
          name != nil,
          reduce: %{} do
        acc -> Plug.Conn.Query.decode_pair({name, body}, acc)
      end
​
    params = case params do
      %{"operations" => operations, "map" => map} ->
        map = Jason.decode!(map)
        operations = Jason.decode!(operations)
​
        # Transform the file map to the query variables
        vars =
          Enum.reduce(map, operations["variables"], fn mapping, vars ->
            {name, [path]} = mapping
            path = String.split(path, ".") -- ["variables"]
            put_in(vars, path, name)
          end)
​
        # New query drops operations/map in favor of query/variables
        params
        |> Map.drop(["operations", "map"])
        |> Map.merge(%{"variables" => vars, "query" => operations["query"]})
​
      _ ->
        params
    end
​
    {:ok, params, conn}
  end
end
sescobb27

sescobb27

for posterity, i adapted some solutions into this with some basic tests and a way to do an integration test absinthe integration with apollo's file upload · GitHub

Where Next?

Popular in Questions Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement