简体   繁体   中英

Why should I use an interface for a GraphQL mutation response type?

In reading the Apollo Server documentation, it recommends using a mutation response interface for mutations:

In order to provide consistency across a schema, we suggest introducing a MutationResponse interface which can be implemented on every mutation response in a schema and enables transactional information to be returned in addition to the normal mutation response object.

https://www.apollographql.com/docs/apollo-server/essentials/schema.html

I understand the benefit of interfaces for use cases where you have an events interface and then you have different types of events such as a concert, conference, etc. My understanding is an interface would allow you to search all events with a single query for example, returning multiple types of events.

I am confused why an interface should be used for a mutation response and what the benefits would be over a standard response type?

Like a Union, an Interface is an abstract type that allows a field to return one of multiple types. From the spec:

Fields which yield an interface are useful when one of many Object types are expected, but some fields should be guaranteed.

However, interfaces also force implementing types to have a specific set of fields and arguments. The exact rules can be found here in the spec, but it boils down to:

  • If the interface has a field, the implementing type must also have that field
  • The implementing type must also have the same arguments for any of these fields (like fields, it can add additional ones, but must at least implement the same ones as the interface)
  • The types of these required fields and arguments must match the interface
  • If the type of a required field or interface is Non-Null, it must also be Non-Null on the implementing type (although the reverse is not true)

By creating an Interface and having multiple types implement it, you effectively create a safety net that will help you ensure a consistent structure across related types. Let's assume we implement some response types as suggested in the Apollo docs, without an interface:

type UpdateUserMutationResponse {
  code: String!
  success: Boolean!
  message: String!
  user: User
}

type UpdatePostMutationResponse {
  code: String!
  success: Boolean!
  message: String
  post: Post
}

At a glance, these types are defined as we intended -- we have fields for code , success and message , along with whatever other fields are relevant for that response. However, we have a type and accidentally made the message field on UpdatePostMutationResponse nullable. While this may be harmless, if we do happen to omit the message in our resolver, it may go unnoticed until way later (hopefully during QA, but maybe in production!).

If we have these types implement a MutationResponse interface, though, we can ensure that our schema won't even build if there's any inconsistencies like that.

In this way, even if we never utilize MutationResponse as a return type for a field, we can still benefit from utilizing an Interface.

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