简体   繁体   中英

What should the response from a GraphQL mutation be?

I'm writing a GraphQL server and am wondering what the response should be from a mutation? For queries, it's obvious: the response consists of what was requested. For a mutation, however, what should the response be or look like? Should the response consists of just a String message letting the consumer know whether the mutation succeeded without errors? Or should the response be the object they mutated?

GraphQL doesn't force this one way or the other, but popular convention is to return the object .

With REST, the understanding is generally that the object which was mutated should be returned as the new state the object is in. This convention has carried over to GraphQL as well, so I would say in most cases you want to return the object.

The GraphQL documentation appears to reinforce this as well:

type Mutation {
  createMessage(input: MessageInput): Message
  updateMessage(id: ID!, input: MessageInput): Message
}

Where in this case createMessage and updateMessage take a MessageInput and return the updated or new Message object.

This also has key practical benefits! For popular GraphQL frameworks like Apollo, returning the result means that Apollo will automatically integrate the updated result into its cache for faster retrieval and rendering later.

Are there situations where you don't want to do this? Definitely. If you are deleting an object, you might want to return only a more simple return type such as the ID or a string that identifies the action was completed.

There are also some operations that don't have a natural object to return, as they don't intuitively tie into a CRUD operation ( promoteUser for example). In REST, it often requires wrapping the operation into an abstract object (such as POST /promoteUserRequest ) to be technically idiomatic, but in GraphQL you can be more flexible (it'd be valid to return the user or also valid to return just a string confirmation).

There is also other belief camps, which advocate this sort of design:

type RootMutation {
  createTodo(input: CreateTodoInput!): CreateTodoPayload
  toggleTodoCompleted(input: ToggleTodoCompletedInput!): ToggleTodoCompletedPayload
  updateTodoText(input: UpdateTodoTextInput!): UpdateTodoTextPayload
  completeAllTodos(input: CompleteAllTodosInput!): CompleteAllTodosPayload
}

In this example from the Apollo blog , it doesn't return a generic Todo type but instead returns a custom type that's specific to each mutation. Some people believe this 1-to-1-to-1 mapping of mutation-input-response is a better approach as it lets you edit individual mutations without worrying about effecting the return / input values of other resolvers. This has also been used for Queries sometimes.

Lastly, keep in mind another GraphQL benefit here: regardless of what you decide to return, the client only has to retrieve it from the result if it makes sense for it to. The client is free to perform the mutation and request all, some, or none of the response type. For comparison, under REST, you are generally forced to receive the whole response.

Overall, I'd say it's a lot more common to return the object, but there is no hard-and-fast rule so you can pick what is ideal for your API.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM