magento / architecture

A place where Magento architectural discussions happen
275 stars 155 forks source link

Proposal (GraphQL): Reconsider direction to favor named arguments over input objects #400

Open DrewML opened 4 years ago

DrewML commented 4 years ago

We currently have the following guidance documented for new handling of input data to an operation:

https://github.com/magento/architecture/blob/master/design-documents/graph-ql/extensibility.md

It states that the solution for extensibility is:

Wrappers for output and merger for arguments

There's a problem with argument lists worth considering.

Example

Imagine this is a mutation in our schema:

type Mutation {
   createFoo(
      arg1: String = "default"
      arg2: Int!
      arg3: String
      arg4: SomeObjectType
   ): CreateFooOutput
}

To use this, pwa-studio will likely parameterize it:

mutation CreateFoo($arg1: String = "default", $arg2: Int!, $arg3: String, arg4: SomeObjectType) {
   createFoo(
      arg1: $arg1
      arg2: $arg2
      arg3: $arg3
      arg4: $arg4
   ) {
      field1
      field2
   }
}

There are a few potential problems I'm aware of in this example:

  1. CreateFoo now has its own default value for arg1. There is no way (that I'm aware of) to define this operation where the default from arg1 will be automatically carried to $arg1. @sirugh hit this issue in pwa-studio recently (they just wanted to use whatever default the server used)
  2. If an optional arg is added to Mutation.createFoo, and a user of pwa-studio wants to use it, they have to change both UI Components and the query itself (rather than just the UI component).
  3. It's very verbose. See this example in pwa-studio.

What is the alternative

The alternative is leaning on Input Object types to act as a bag of named arguments.

Re-Written Example

type Mutation {
   createFoo(input: CreateFooInput): CreateFooOutput
}

input CreateFooInput {
   arg1: String = "default"
   arg2: Int!
   arg3: String
   arg4: SomeObjectType
}
mutation CreateFoo($input: CreateFooOutput) {
   createFoo(input: $input) {
      field1
      field2
   }
}