-
-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simple alternative if you are not tied to the JS graphql ecosystem. #50
Comments
I've left this open until I had the time and mental energy to compose an adequate response. I had planned to go above and beyond by digging up all the technical reasons we abandoned similar ideas to replace files with unique IDs in the early research and development days, but as reasoned below I don't think such effort is required to close this issue. If you’re curious about the history, there is a fair bit to read in old PR's and issues in this repo and the The first thing that comes to mind (although it's a pretty exotic) is that the current spec allows files to be used anywhere in the GraphQL operations objects, not just in With your proposal that doesn't include a map of where files are used in the operations, it's not clear to me how one file variable used as an argument in multiple mutations in the same request could be implemented on the server. Is that something you have considered? Performance wise the map allows the server to cheaply see up front how many files there are, and where they are expected to be used in the operation without having to parse the GraphQL query looking for certain upload scalars in an AST, etc. For example, the map makes implementing the
The point of this spec is to create a standard for interoperability between all GraphQL clients and servers, regardless of the languages or ecosystems. A spec that’s incompatible or overly burdensome to a JS browser implementation or a Node.js I welcome constructive criticism around this spec that is actionable, but it seems you’re proposing an alternative with conflicting goals. Please exercise caution as multiple different specs for multipart GraphQL requests would be an interoperability disaster for the GraphQL community, beyond the JS GraphQL ecosystem. At this point, this spec and it's numerous implementations have matured, so not aligning with the greater community will have significant productivity costs to your team. You won't be able to use the nice Altair playground GUI to test file upload variables, you won't be able to easily swap out your GraphQL client or server implementation without rewriting the other end, etc. etc.
This spec and the Here is a breakdown of the
Overally, it appears your proposed spec would not really decrease implementation complexity, and in some cases it might actually increase it. Probably UUID is overkill; perhaps your proposal could be simplified to IDs that are only unique amongst the sibling multipart request field names.
Disagree that it's semantically questionable; please see #4 (comment) . Further discussion here is welcome; closing because at this point I don't plan to action the suggestions raised in this issue in a major breaking spec change. |
I'd like to reopen this discussion on @enjoylife's suggested simplification of the spec. I believe their suggestion can greatly simplify this specification and ease the implementation for typesafe frameworks while still achieving the original goals for JS GraphQL libraries. Just for clarity, this is a rough draft of how I imagine the new version of the spec could look building off of what @enjoylife has defined:
ex: curl http://localhost:4000/graphql \
-F gql='{ "query": "mutation { upload(files: [\"file_id\"]) }", "variables": null }' \
-F [email protected] I've implemented a prototype of this in my own Scala server and I have a very rough implementation of this for Apollo: Prototype Apollo Attachments Gist Regarding the comments in #11 (describing how the This is a trace from running my gist:
You can see that we've achieved the same async waterfall where our GraphQL request execution starts immediately.
Yes, each file is always referenced by its An added benefit of this proposal over the current spec is the ability to define file references outside of variables. Right now you're required to always have a
This doesn't really change between the current spec and this proposal. You're always looking up in your context for the file based on its uid. There's no reason you can't repeatedly query the same file based on its uid. ex:
Although this is true of the new spec change, we'll always be parsing GraphQL requests in GraphQL servers, it's a matter of leveraging the server libraries to facilitate this. This is something that could maybe be handled by an Apollo Even if we're writing an implementation of this spec for a framework that gives 0 options to validate our GraphQL request, the current JS spec implementation has already defined code that would catch maxFiles as they were streaming through via
Exactly, this spec appears to be designed in order to run as a JS Server middleware. There is a good amount of indirection, implementation specific solutions, and dependencies on the implementing language/framework. This all creates more work for server implementers. I did an audit of the various server implementations and all of the ones I looked at either depend on:
There doesn't seem to be a good way to add this specification to a typesafe language/framework without it devolving into the proposed spec change. For Example
|
I've opened #55 to continue the discussion |
TL;DR If you are not using a server side graphql implementation with limitations on how scalars and other types should be "resolved", (such limitations arise in the apollo's js server see #11 and here) and your not tied to graphql-upload. Then I would not recommend using this spec verbatim. Instead just use uuid's to map between the schema and each body part.
The environment I'm assuming is on client side, we collect files from a
<input type="file" />
element providingFile
objects. We ultimately want to use theseFile
objects as variables within our request. Now instead of doing the funkynull
replacement which this spec defines, which is semantically questionable, just use the scalar to hold a uuid and use it when to constructing requests. High level steps:{variables: files:[ {uuid: 'xxx'} ]
Following such an approach creates a curl request along the lines of:
Then server side you simply read off the first part of the body which holds the query. Pretty much every graphql implementation gives you access when parsing the ast, and you can execute the schema as desired having read that first part. Now there you could either block and consume all the remaining parts, setting them aside in memory or temp files, which the resolvers would use as a lookup per each file variable uuid. Or you can read the parts as needed, streaming in the data, and have the resolvers, waiting in parallel for other resolvers to consume the body up to the needed part.
For additional clarity here’s an outline for given a Js client and Go server setup.
1 Set uuid's on the files to upload
Map the variables to satisfy the schema
{variables: files:[ {uuid: 'xxx'} ]
Fire off the request appending on the file(s) using the uuid as the multipart name
Server Side rough example:
In the resolvers....
If you made it thus far, I just want to remind you that if you are using apollo or any of the heavy js graphql abstractions, this projects spec is good and correctly works within the limitations of node and the rest of the node based graphql libraries. But if your outside of that world, this simple uuid mapping like I have outlined above is a simple alternative.
The text was updated successfully, but these errors were encountered: