GraphQL
Operation Types:
Schemas
# this is the root object{}# fields can be selected on this{ dog}# fields of that field can also be selected{ dog { name }}Types
Query and Mutation
# query and mutation types specify fields that can be queriedtype Query { dog(name: String): Dog}type Mutation { addFriend(name: String, friend: Dog): Dog}Scalar Types
StringIntFloatBooleanID # a special type of String, unique for each value# scalars can be added (although not all# implementations support this)scalar DateEnums
enum Interval { YEAR DOGYEAR DAY}Null
# an exclamation point means a field cannot be null# if the value is null, an execution error will occurtype Dog { name: String!}# error response{ errors: [ { message: "...", locations: [ { line: 1, column: 2 } ] } ]}Objects
# object types describe objects that can be fetched and their fieldstype Dog { name: String! breed: String! # fields describe functions. The default is a function with zero # arguments, which doesn't need to be specified. Default values can be # provided to make arguments optional. age(unit: Interval = YEAR): Float!}Lists
type Dog { # arrays are specified with square brackets friends: [Dog]}# array can be null, but dogs cannotfriends: [Dog!]# array cannot be null (will return empty array if no matches)friends: [Dog]!Interface
# interfaces define required fieldsinterface Animal { id: ID! name: String!}# types can implement an interfacetype Dog implements Animal { id: ID! name: String! age: Float!}type Cat implements Animal { id: ID! name: String! lives: Int!}# interfaces can be the type for a fieldtype Query { GetAnimal($name: String!): Animal}# however, you can only query on fields of the interfacequery GetAnimal($name: String!) { # this will cause an error age}# inline fragments allow you to query type specific fieldsUnion
# a union groups types (not interfaces!), but without common fieldsunion Thing = Dog | Cat | Tree# this can be useful for tasks that can return multiple typesInput Types
# input types look like regular types, but are specified# with the input keywordinput DogInput { name: String! breed: String!}# input types are passed to mutationsResolvers
# resolvers are functions associated with a field# if a resolver returns a scalar, then it stops. For other# types, it goes deeper (to that type's fields){ dog { name: String!, # string, stops friends: [Dog]! # object, so keeps going }}// resolvers receive four arguments:// 1. obj is the previous object (one level up, not old)// 2. args are arguments provided in the field's query// 3. context extra, useful data// 4. info about query's execution state (use rarely){ Query: { dog(obj, args, context, info) { return api.getDog(args.id).then(data => { return new Dog(data); }); } }, Dog: { name(obj, args.context) { return obj.name } }}Introspection
Useful for exploring the GraphQL structure.
Query
# the query operation type indicates that some gql is a queryquery { ...}# this isn't required, but is useful for clarity# a query gets data# the query specifies the shape of the data it wantsquery { dog { breed }}# the returned object has properties of the same shape# as the query{ data: { dog: { breed: "corgi" } }}query { # you can also insert comments into a query dog}# subquery with nested propertiesquery { dog: { name, friends: { name } }}# returns{ data: { name: 'Ralph', friends: [ { name: 'Spot' }, { name: 'Fido' } ] }}Arguments
query { dog(id: "k9") { name, breed }}# returns dog that matches the id{ data: { dog: { name: 'Sahara' } }}# sub-properties can also be queriedquery { dog(id: "k9") { weight(unit: KG) }}{ data: [ dog: { weight: 23 } ]}Aliases
# properties can be aliased, which is helpful with duplicatesquery { shortDog: dog(breed: "dachsund") { name }, tallDog: dog(breed: "great dane") { name }}{ data: { shortDog: { name: 'Goliath' }, tallDog: { name: 'Tiny' } }}Fragments
# fragments let you define partial queries, which can# be included as parts of a larger queryquery { shortDog: dog(breed: 'chihuahua') { ...quantitativeFields }}fragment quantitativeFields on Dog { height weight age}# inline fragments can be used to specify properties# based on a type, which is useful for subtypesquery { animal { name ... on Dog { age } ... on Cat { lives } }}# these can be combined with named fragments,# which already include an "on"query { animal { name ...dogProperties ...catProperties }}fragment dogProperties on Dog { age}fragment catPropeties on Cat { lives}Operation Name and Variables
# an operation name is like a function namequery DogData { dog { name breed age }}# operations must be named to pass dynamic variables# variables start with $.# The type of the variable must be provided.# The exclamation point indicates this variable is requiredquery DogData($name: String!) { dog(name: $name) { name breed age }}# default variables can be providedquery DogData($name: String = "Terra") { dog(name: $name) { ... }}Meta
query { dog { # __typename returns an object's type # this is useful for queries that can return # multiple types __typename }}Directives
# directives can be used to control whether# part of a query is includedquery DogData($name: String!, $andFriends: Boolean!, $withAge: Boolean!) { dog(name: $name) { name breed # only @include friends when andFriends is true friends @include(if: $andFriends) { name breed } # you can also $skip fields age @skip(if: $withAge) }}Custom Directives
While GraphQL includes the @skip and @include directives, it is possible to write your own as well.
The exact implementation varies by GraphQL framework.
When defining a directive in a schema, it requires a name and what it can be added to (fields, types, etc.). The directive can also take arguments.
directive @yo( arg: String = "default value") on FIELD_DEFINTIONquery { dog { name @yo }}Mutations
# while queries read data,# mutations are used for setting/modifying datamutation AddFriend($name: String!, $friend: String!) { addFriend(name: $name, friend: $friend) { # you can return the results of the mutation name friends { name } }}# an operation can contains multiple mutations# they will be run consecutively, not at the same time