smee2
April 15, 2021, 12:28am
1
Hey folks! I have a GraphQL API for a Strapi-powered backend app, with an “items” table and an “images” table. In the items table there is a column for an optional “imageID” foreign key.
I want to create a mutation for a new item and want to give it an imageID, but the image file should be freshly uploaded with the rest of the item details and doesn’t have an ID yet.
So I’m trying to write the mega-mutation a bit like this, using createItem()
and upload()
mutation CREATE_ITEM_MUTATION(
$name: String!
$image: Upload
) {
createItem(
input: {
data: {
name: $name
image: {
upload(file: $image){
id # <======= this is what I need to pass in as the "image" value to createItem
}
}
}
}
) {
item {
id
size
}
}
}
But the GraphQL playground yells at me for a syntax error where I use the upload(
above: Expected Name, found (
.
So my question is: how do I grab the imageID
from the upload
method and pass it in to its parent, createItem
method? (Is that even possible?)
marc
April 21, 2021, 1:31pm
2
Pardon me, @sunnyson , @DMehaffy , others, is this possible ? It would be awesome if this is possible.
smee2:
Is that even possible?
Short answer: No
Take a look at these useful resources:
opened 06:43AM - 17 Dec 16 UTC
💭 Strawman (RFC 0)
In the current GraphQL specification the schema type have three different types … on it: `query`, `mutation` and `subscription`.
The **mutation** type is a special `ObjectType` that **enforces the fields on it to be resolved `serially`** instead of in `often parallel` as could happen in fields in any other type
>When executing a mutation, the selections in the top most selection set will be executed in serial order. [[1]](https://facebook.github.io/graphql/#sec-Normal-and-Serial-Execution).
But this "mutation" type declaration is not self-contained: when defined in a schema as mutation it have a side effect on the execution of a query, making their fields to be executed serially.
Because of there is only one type in a schema that enforces a serial evaluation on their subfields, all "mutation fields" are forced to be in the Mutation type itself.
Having all "serial resolved fields" in only one types causes the Mutation type (schema.mutation) to be an `ObjectType` with over bloated fields on it, that have not common ground between them other than serial execution.
# Proposal
Would be great if instead of having all the mutations in a first type class (where it's execution depends on the Schema for knowing if it should be resolved serially or not), we could be able to mutate in a generic GraphQL query, in any kind of type level.
Would be great, if instead of doing:
```graphql
mutate MyMutation {
postToUserTimeline(userId: "1", commentContent: "Happy Birthday Mark!") {
comment { # The new created comment in Mark's timeline
id
content
}
user {
timeline {
id
content
}
}
}
}
```
We could be able to do serial resolution on certain fields:
```graphql
{
getUser(id:"1") {
postToTimeline(commentContent:"Happy Birthday Mark!") { # serial field
comment {
id
}
}
allComments {
id
comment
}
}
}
```
### Composing mutations
With the ability to have "mutation / serial fields" in any kind of type, we could start doing things like:
```graphql
{
user(id:"1") {
postToTimeline(commentContent:"Happy Birthday Mark!") { # This is a serial field
comment {
addReaction(reaction: LIKE) # This is another serial field, that adds a reaction into the comment
}
}
}
}
```
### Execution showcase
The following example hopefully will showcase how the field resolution could be done:
```graphql
{
user(id:"1") {
postToTimeline # serial
comments # normal
photos # normal
tagPhoto # serial
postAgain: postToTimeline # serial
secondPhotos: photos # normal
secondComments: comments # normal
}
}
```
In this case, the execution will done serially as follows:
* Resolve `postToTimeline` (not resolve any other field until this is resolved)
* Resolve `comments`, `Photos` normally (often in parallel)
* Resolve `tagPhoto`
* Resolve `postAgain`
* Resolve `secondPhotos` and `secondComments` normally (often in parallel)
## How could be implemented
This could be easily solved by creating a adding a `isMutation` (`isSerial` maybe is better?) attribute inside the Field.
In the previous example, `postToTimeline` will be executed serially first, then in parallel all the subsequent fields until another "serial field" (field with `isSerial=true` on it) is found, and so on.
## Why of this proposal
There is a lot of tooling that could be created specifically around mutations, and this would help a lot for it, apart from simplifying the schema execution (as are now will be the fields the ones that define if they want to be executed serially or not) and mutations composition.
---
Related issues: #247
There a lot of things to improve, define better and discuss further, so any thoughts and feedback is more than welcome! 😊
Discover the benefits of offering nested mutations as an opt-in feature in your GraphQL server, including a slimmer, more manageable schema.
Est. reading time: 12 minutes