feat: support standard graphql-multipart-request-spec for file uploads#309
feat: support standard graphql-multipart-request-spec for file uploads#309donleandro wants to merge 2 commits intoabsinthe-graphql:mainfrom
Conversation
Add support for the widely-used graphql-multipart-request-spec format (https://github.com/jaydenseric/graphql-multipart-request-spec) used by Apollo Client, urql, Relay, and most GraphQL clients. The implementation transforms the standard format (operations + map fields) into Absinthe's native format before it reaches the pipeline, so the existing :upload scalar works without changes. This is fully backward compatible - the current Absinthe-specific upload format continues to work as before. Supports single file, multiple files, and batched operations. Closes absinthe-graphql#296
benwilson512
left a comment
There was a problem hiding this comment.
Hey there!
While in general we have favored doing this sort of thing as an external package, this is an area where the graphql spec itself doesn't have an opinion AND Absinthe has created its own workaround, so we may as well support a broader community approach. This is also MUCH nicer than an older way of doing this which abused null variables.
The "Changes Requested" part of this is documentation. We need to update the relevant documentation to make it clear we support this spec.
Update Types moduledoc with standard spec examples and usage guide. Add File Uploads section to README showing the recommended approach. Add changelog entry for the new feature.
|
Added the documentation updates:
About the CI failure on the first commit: the failing test is the subscription SSE test (line 553) hitting a race condition with |
Hey all! We ran into this while building Shiko, a veterinary clinic management platform. We needed file uploads over GraphQL (images, documents, etc.) and found that standard clients just wouldn't work with Absinthe's custom upload format.
We initially worked around it with a REST endpoint for uploads, but having half the API on GraphQL and half on REST felt wrong. After digging into the source, we realized the issue was well-known (#296) but nobody had sent a fix yet, so here we are.
What this does
Adds support for the graphql-multipart-request-spec, which is the standard used by Apollo Client, urql, Relay, Flutter clients, and basically every other GraphQL ecosystem out there.
The approach is simple: when a request comes in with
operations+mapfields (the standard format), we transform it into Absinthe's native format before it hits the pipeline. This means::uploadscalar works without any changesHow it works
The standard spec sends:
We parse
operationsandmap, then replace thenullplaceholders in variables with the form field name strings (e.g.,"0"). Since those field names already exist asPlug.Uploadstructs inconn.params, the existinguploaded_files/1function picks them up and the:uploadscalar resolves them as usual.Testing
Closes #296