33

If I have a set of field that is common to multiple types in my GraphQL schema, is there a way to do something like this?

type Address {
  line1: String
  city: String
  state: String 
  zip: String
}

fragment NameAndAddress on Person, Business {
  name: String
  address: Address
}

type Business {
   ...NameAndAddress
   hours: String
}

type Customer {
   ...NameAndAddress
   customerSince: Date
}
Good Idea
  • 2,481
  • 3
  • 18
  • 25

3 Answers3

18

Fragments are only used on the client-side when making requests -- they can't be used inside your schema. GraphQL does not support type inheritance or any other mechanism that would reduce the redundancy of having to write out the same fields for different types.

If you're using apollo-server, the type definitions that make up your schema are just a string, so you can implement the functionality you're looking for through template literals:

const nameAndAddress = `
  name: String
  address: Address
`

const typeDefs = `
  type Business {
     ${nameAndAddress}
     hours: String
  }

  type Customer {
     ${nameAndAddress}
     customerSince: Date
  }
`

Alternatively, there are libraries out there, like graphql-s2s, that allow you to use type inheritance.

Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183
  • 12
    I find it strange that this isn't supported in GraphQL. It's the case that a type and its corresponding input have a lot of shared fields. Using string interpolation means I can't use just plain `.graphql` files. It also means another language can't use that same `.graphql` file. Seems like this should really be supported in GraphQL. – Brennan Cheung May 25 '18 at 22:53
  • 1
    It is pretty strange there is no type inheritance. – A.com Jul 30 '19 at 13:29
  • Is there an update on this ? – Dominik Reinert Jul 19 '22 at 07:13
5

You can, but GraphQL won't let you make a fragment between 2 types unless you specify into the schema that those types are sharing the same properties. To do so, you have to use an interface. You will then be able to build a fragment of this interface on the client side.

Server side schema:


interface NameAndAddress {
  name: String
  address: Address
}


type Address {
  line1: String
  city: String
  state: String 
  zip: String
}

type Business implements NameAndAddress {
  # by design you have to write those properties again
  name: String
  address: Address

  hours: String
}

type Customer implements NameAndAddress {
  name: String
  address: Address

  customerSince: Date
}

Then on your client

# define a fragment on the interface
fragment NameAndAddress on NameAndAddress {
  name: String
  address: Address
}

# you can then get the fields as follow
query {
  business {
     ...NameAndAddress
  }

  customer {
     ...NameAndAddress
  }
}

Flavien Volken
  • 19,196
  • 12
  • 100
  • 133
3

Don't know if it was not available at this question time, but I guess interfaces should fit your needs

aleclofabbro
  • 1,635
  • 1
  • 18
  • 35