Search code examples
reactjsgraphqlapolloapollo-client

GraphQL Save a form


I would like to save a big form by GrahQL and React. I have all of the form values in one variable name: formValue Is there any way to pass "formValue" to the query like this?

const [toSaveUserProfile] = useMutation(SAVE_USER_PROFILE)
toSaveUserProfile({ variables: formValue })

const SAVE_USER_PROFILE = gql`
  mutation saveUserProfile($profileId: String!) {
    updateProfile(profile: { formValue }) {
     id
    }
  }
`

or I should pass all of the fields one by one and define their types like this?

const [toSaveUserProfile] = useMutation(SAVE_USER_PROFILE)
toSaveUserProfile({ variables: formValue })

const SAVE_USER_PROFILE = gql`
  mutation saveUserProfile($id: String!, $firstName: String, $lastName: String, $age: Int, ......) {
    updateProfile(profile: { id: $id, firstName: $firstName, lastName: $lastName, age:$age, ......}) {
      id
    }
  }
`

the schema looks like something like this

updateProfile(profile: ProfileDTOInput!): ProfileDTO

type ProfileDTO {
  address: String
  emails: String
  employeeId: String
  firstName: String
  lastName: String
  age: Int
  phone: [PhoneDTO]
}

input ProfileDTOInput {
  lastName: String
  phone: [PhoneDTO] 
  address: String
  age: Int
  employeeId: String
  emails: String
  firstName: String
} 

type PhoneDTO {
  number: String
  phoneType: String
}

input PhoneDTOInput {
  phoneType: String
  number: String
}

Solution

  • You should use the GraphQL input type for this scenario. Why? GraphQL input types are useful for keeping argument definitions short and sweet, especially in cases like yours. For instance, this:

    mutation saveUserProfile($id: String!, $firstName: String, $lastName: String, $age: Int, ......)
    

    has the potential to expand to an endless list of arguments for the mutation you've defined. Not only is this hard to write, but it is also hard to maintain and read.

    Instead, using an input type would simplify this greatly.

    input SaveUserProfileInput {
      id: ID!
      firstName: String
      lastName: String
      ...
    }
    
    mutation saveUserProfile($input: SaveUserProfileInput!) {
      updateProfile(input: $input) {
        ...rest of your code here...
      }
    }
    

    Your mutation now only takes one argument -- an input type -- which is defined on its own. As the schema designer, you can expand these fields however you like, in a single place. Your mutation definition, and the arguments that it takes, will never need to change.

    Note that you'll need to change the schema definition of your mutation updateProfile to accept an input as an argument of type SaveUserProfileInput (or whatever you have named it) if you follow this approach.

    For more information on input types, I suggest looking at this great post by Daniel Rearden:

    https://stackoverflow.com/a/55881719/4301222