# GraphQL : Standard \[ [spec](https://spec.graphql.org/October2021/) | [site](http://graphql.org/) ] - Language-agnostic, though the [reference implementation](https://github.com/graphql/graphql-js/) is in JavaScript. - Transport-agnostic, though mostly used with HTTP with JSON payloads. - Both schemas and queries are described in GraphQL "documents". - Mutations are syntactically identical to queries, but are allowed (by convention) to have "side-effects". - The root fields of the Mutation type are guaranteed to be called serially, rather than in parallel. ## Types #### Terms - **Abstract** ­— Interface and Union - **Concrete** — Enum, Object, Scalar - **Enum** — special kind of Scalar with explicit value set - **Fields** — can take arguments (scalars and input types) and return any non-input type - **Input** — like Object types, but contains input fields, and is used as arguments to fields - **Input Fields** — cannot take arguments, and can only return scalars or other input types - **Interface** — defines the set of fields an Object type must include to implement the Interface - **Mutation** — starting point for all mutation operations - **Object** — contains fields which can also be objects - **Query** — starting point for all query operations - **Root** — sometimes refers to the Query type, sometimes to any of the three root types (Query/Mutation/Subscription), which are Object types - **Scalar** — Boolean, Float, ID (string), Int, String - **Subscription** — starting point for all subscription operations - **Union** — set of Object types that can be returned by a field #### Syntax - comments (`#`) are allowed - newlines are optional except to terminate comments - commas are optional - names can be composed of: `A-Za-z0-9_` (don't start with `__`) - types are nullable by default - non-nullable type T expressed as: `T!` - list of type T expressed as: `[T]` - also non-nullable list of T: `[T]!` - and list of non-nullable T: `[T!]` - custom scalars are treated like strings, but *should* specify a human-readable reference ###### Scalars ```graphql # scalar <name> @specifiedBy( url: "..." ) scalar Date @specifiedBy( url: "https://tools.ietf.org/html/rfc3339" ) # enum <name> { <values> } enum LengthUnit { FOOT, METER } ``` ###### Fields ```graphql # <name>: <type> height: Float # <name>( <arg>: <type> ): <type> height( unit: LengthUnit ): Float # <name>( <arg>: <type> = <default> ): <type> height( unit: LengthUnit = FOOT ): Float ``` ###### Objects, Inputs, and Abstract ```graphql # type <name> { <fields> } type Starship { id: ID!, name: String!, model: String! } # interface <name> { <fields> } interface Character { id: ID!, name: String! } # type <name> implements <interface> { <fields> } type Person implements Character { id: ID! name: String! species: String! height( unit: LengthUnit = FOOT ): Float } # union <name> = <type> | ... union SearchResult = Person | Starship # input <name> { <fields> } input ReviewInput { stars: Int, commentary String } ``` ###### Root Types ```graphql # schema { query: <type>[, mutation: <type>][, subscription: <type>] } # optional if you stick with the default type names schema { query: Query, mutation: Mutation } # type <root-type> { <root-fields> } # only required to define query root type type Query { hero: ID! char( id: ID! ): Character search( query: String! ): [ SearchResult! ]! } ``` ## Documents #### Terms - **GraphQL Document** — A string written in the GraphQL Schema Language that defines one or more Operations and Fragments. - **Operation** — A single Query, Mutation, or Subscription that can be interpreted by a GraphQL execution engine. - **Operation Type** — Either `query`, `mutation`, or `subscription`. - **Operation Name** — (OPTIONAL) It’s useful to give your Operations meaningful names for debugging and logging. - **Variable Definition** — The list of Variables (name and type) accepted by an Operation. - **Variable** — A dynamic parameter passed to an Operation. Must be a Scalar, Enum, or Input Type. Values must be provided in a separate, transport-specific (usually JSON) variables dictionary. - **Selection Set** — The set of fields requested in an Operation or nested within another field. (The `{ <fields> }` block.) - **Field** — A field on the parent object. Can accept Input Arguments. Any field that returns an Object Type must contain a Selection Set on that field. (No `SELECT *`.) - **Input Argument** — A value passed to a field's Resolver. - **Fragment** — Fragments are the primary unit of composition, and allow for reuse of common Selection Sets. Can be Named or Inline, and are used inside Operations and other Fragments. - **Fragment Definition** — Defines a Named Fragment. - **Fragment Name** — The name of a Named Fragment. Used to refer to fragment in operations or other fragments, and in debugging/logging. - **Named Fragment** — Defined separately, given a name so it can be used, and a Type Condition so it can be validated against the schema. - **Inline Fragment** — Used to conditionally access fields on the Concrete Type underlying the Interface or Union Type. - **Type Condition** — The `on <Type>` that indicates what Object, Interface, or Union Type a Fragment expects. - **Spread Operator** — The `...` operator. Includes the contents of a Fragment into the parent Selection Set. - **Directive** — An annotation on a field, Fragment, or Operation that affects how it is executed or returned. - **Directive Argument** — Like Input Arguments, but are handled by the execution engine instead of being passed down to the field Resolver. #### Syntax ###### Operation ``` # { <fields> } { hero } # operation type assumed to be "query" # w/field alias { fool: hero } # <OperationType> { <fields> } query { hero } # <OperationType> <OperationName> { <fields> } query GetHero { hero } # <OperationType> ( lt;Variable>: <Type>, ... ) { <fields> } query ( $CharID: ID! ) { char( id: $CharID ) { name } } # <OperationType> <OperationName>( lt;Variable>: <Type>, ... ) { <fields> } query GetChar ( $CharID: ID! ) { char( id: $CharID ) { name } } ``` ###### Named Fragments ``` # defining a fragment: # fragment <name> <TypeCondition> { <fields> } fragment CharFields on Character { id, name } # using a fragment in field selection set: query ( $CharID: ID! ) { char( id: $CharID ) { ...CharFields } } ``` ###### Inline Fragments ``` # ... <TypeCondition> { <fields> } query ( $CharID: ID! ) { char( id: $CharID ) { name ... on Person { species } } } ``` ###### Directives ``` @include( if: lt;var> ) @skip( if: lt;var> ) # on a field: <Field> <Directive> { <fields> } # on a named fragment: ...<Fragment> <Directive> # on an inline fragment: ... <TypeCondition> <Directive> { <fields> } ``` ## Introspection - We can ask GraphQL what types are available by querying the `__schema` field, always available on the Query Type. - You can request `__typename`, a Meta Field, in any Selection Set to get the name of the Object Type at that point. ###### Introspection Types ```graphql __Schema, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive ``` ###### Introspection Schema ```graphql __schema queryType name types name __type(name: <Name>) description fields name type kind # ex: INTERFACE, LIST, NON_NULL, OBJECT, SCALAR name ofType # for "wrapper" types (LIST and NON_NULL) # returns type of value contained within ``` ## Transport (Best Practices) - Service mounted at single endpoint (usually `/graphql`). - Should handle both `GET` and `POST` methods, with three params: - query — document containing one or more operations - variables — encoded as JSON - operationName — if query contains multiple named operations, specifies which one to execute #### Request - **GET:** `https://myapi/graphql?query=<GraphQLDocument>&variables=<Variables>&operationName=<OperationName>` - **POST:** Use the `application/json` content type, and include a JSON-encoded body with the parameters. #### Response The response should be returned in the body of the request in JSON format. - If there were no errors returned, the "errors" field should not be present on the response. - If no data is returned, according to the GraphQL spec, the "data" field should only be included if the error occurred during execution. ```json { "data": { ... }, "errors": [ ... ] } ``` ## Execution A Resolver function receives three arguments: - *obj* — The previous (parent) object, which for a field on a Root Type is generally not used. - *args* — The field's Input Arguments. - *context* — A value provided to every Resolver with contextual information, like the DB handle or current user.