elm-graphql
elm-graphql copied to clipboard
Add an ability to upload files
It will be good to add something like withFiles : List ( String, File.File ) -> Request decodesTo -> Request decodesTo so it will be possible to upload files alongside with query.
It will require to send request as POST with multipart/form-data though so it will overwrite things like QueryRequestMethod silently.
Sending files over GraphQL is not a part of official spec but supported by many frameworks:
- https://hexdocs.pm/absinthe/file-uploads.html
- https://github.com/jaydenseric/graphql-multipart-request-spec (see many server-side implementations at the bottom of README).
Hey @ssbb, thank you for opening the issue!
It looks like both the Absinthe and multipart-request-spec use a Scalar type called Upload. I tried generating some code using an Absinthe test server and it generated this with dillonkearns/elm-graphql:
module Swapi.Scalar exposing (..)
# ...
type Upload
= Upload String
module Query exposing (..)
# ...
type alias SendFileRequiredArguments =
{ file : Swapi.Scalar.Upload }
sendFile : SendFileRequiredArguments -> Field String RootQuery
sendFile requiredArgs =
Object.fieldDecoder "sendFile" [ Argument.required "file" requiredArgs.file (\(Swapi.Scalar.Upload raw) -> Encode.string raw) ] Decode.string
Given that this is treated like a special type, it seems like it would be nice to treat this scalar as a special thing and require a file to be passed in here.
So the generated code could just change the underlying type of the scalar
type Upload
= Upload File
The Encode module would then have to take on some more complexity, doing more than just turning it into a simple GraphQL query... instead, it would have to encode the files as nulls, or [null, null] lists. Then the Graphql.Http module would have to look for any files and figure out where to send them somehow... Anyway, that will be a pretty major design process and will require some thought.
But I think that it's worth experimenting with that approach. Just adding a Graphql.Http.withFiles function that let's you manually add in files which may not be under the correct keys... or that lets you forget to add files, etc., just doesn't feel right given the goals of the library to guarantee correctness. I wouldn't want it to be that it "guarantees correct queries, unless you add files"!
What do you think?
Hi @dillonkearns, thanks for quick detailed reply 👍
I am not sure it's good idea to rely on Upload just by name. It can be used for other purposes as well. Maybe when #39 will be implemented?
My idea was to give a bit more control over HTTP request. Files can be not related to GraphQL at all, right? Like you sending normal GraphQL query and files at the same time (w/o affecting query with things like Upload scalar at all) and back-end know how to work with it. But files here not related to GraphQL at all.
BTW graphql-multipart-request-spec using a bit different approach - request should contain map field with JSON-encoded field/file mapping.
A small bump to this issue as I ran into it today with a gqlgen server.
I had to bypass elm-graphql by manually creating the query and using a request with Http.multipartBody.
Hey @pdamoc , the last I checked file uploads weren't part of the spec in a concrete and standardized way, so I'm actually not sure there a clear and actionable thing that can be done here that follows a the spec.