GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn't tied to any specific database or storage engine and is instead backed by your existing code and data.
At its simplest, GraphQL is about asking for specific fields on objects.
This is essential to GraphQL, because you always get back what you expect, and the server knows exactly what fields the client is asking for.
Every field and nested object can get its own set of arguments, making GraphQL a complete replacement for making multiple API fetches. You can even pass arguments into scalar fields, to implement data transformations once on the server, instead of on every client separately.
GraphQL comes with a default set of types, but a GraphQL server can also declare its own custom types, as long as they can be serialized into your transport format.
Aliases allow you to rename the result of a field to whatever you want.
GraphQL includes reusable units called fragments. Fragments let you construct sets of fields, and then include them in queries where you need to.
The concept of fragments is frequently used to split complicated application data requirements into smaller chunks.
The operation name is a meaningful and explicit name for your operation. It is only required in multi-operation documents, but its use is encouraged because it is very helpful for debugging and server-side logging.
When something goes wrong it is easier to identify a query in your codebase by name instead of trying to decipher the contents.
GraphQL has a first-class way to factor dynamic values out of the query, and pass them as a separate dictionary. These values are called variables.
When we start working with variables, we need to do three things:
- Replace the static value in the query with
$variableNameas one of the variables accepted by the query.
- Pass variableName: value in the separate, transport-specific (usually JSON) variables dictionary.
A directive can be attached to a field or fragment inclusion, and can affect execution of the query in any way the server desires. The core GraphQL specification includes exactly two directives, which must be supported by any spec-compliant GraphQL server implementation:
@include(if: Boolean) Only include this field in the result if the argument is true.
@skip(if: Boolean) Skip this field if the argument is true.
Any query could be implemented to cause a data write. However, it is useful to establish a convention that any operation that causes writes must be explicitly sent through a mutation.
Similar to queries, if the mutation field returns an object type, you can request nested fields. This can be useful to get the new state of an object after an update.
If you are querying a field that returns an interface or a union type, you will need to use inline fragments to access data on the underlying concrete type.
Every GraphQL service defines a set of types which completely describe the set of possible data you can query on that service. Then, when queries come in, they are validated and executed against that schema.
GraphQL services can be written in any language. The "GraphQL schema language" - it's similar to the query language, and allows us to talk about GraphQL schemas in a language-agnostic way.
The most basic components of a GraphQL schema are object types. In the GraphQL schema language, we might represent it like this:
Characteris a GraphQL Object Type, meaning it's a type with some fields. Most of the types in your schema will be object types.
appearsInare fields on the Character type. That means that name and appearsIn are the only fields that can appear in any part of a GraphQL query that operates on the ‘Character’ type.
Stringis one of the built-in scalar types - these are types that resolve to a single scalar object, and can't have sub-selections in the query.
[Episode!]!represents an array of Episode objects. Since it is also non-nullable, you can always expect an array (with zero or more items) when you query the ‘appearsIn’ field.
Every field on a GraphQL object type can have zero or more arguments. All arguments in GraphQL are passed by name specifically, can be either required or optional. When an argument is optional, we can define a default value - if the unit argument is not passed, it will be set to METER by default.
Every GraphQL service has a query type and may or may not have a mutation type. These types are the same as a regular object type, but they are special because they define the entry point of every GraphQL query.
Mutations work in a similar way - you define fields on the Mutation type, and those are available as the root mutation fields you can call in your query.
Scalar types represent the leaves of the query. We know this because those fields don't have any sub-fields - they are the leaves of the query.
GraphQL comes with a set of default scalar types out of the box:
Int: A signed 32‐bit integer.
Float: A signed double-precision floating-point value.
String: A UTF‐8 character sequence.
Boolean: true or false.
ID: The ID scalar type represents a unique identifier The ID type is serialized in the same way as a String.
Also called Enums, enumeration types are a special kind of scalar that is restricted to a particular set of allowed values. This allows you to:
- Validate that any arguments of this type are one of the allowed values.
- Communicate through the type system that a field will always be one of a finite set of values.
The Non-Null type modifier be used when defining arguments for a field, which will cause the GraphQL server to return a validation error if a null value is passed as that argument, whether in the GraphQL string or in the variables.
Lists work in a similar way: We can use a type modifier to mark a type as a List, which indicates that this field will return an array of that type.
The Non-Null and List modifiers can be combined.
An Interface is an abstract type that includes a certain set of fields that a type must include to implement the interface.
Interfaces are useful when you want to return an object or set of objects.
Union types are very similar to interfaces, but they don't get to specify any common fields between the types.
In the GraphQL schema language, input types look exactly the same as regular object types, but with the keyword input instead of type.
The fields on an input object type can themselves refer to input object types, but you can't mix input and output types in your schema. Input object types also can't have arguments on their fields.
After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested query, typically as JSON.
Each field on each type is backed by a function called the resolver which is provided by the GraphQL server developer. When a field is executed, the corresponding resolver is called to produce the next value.
- GraphQL.js: The reference implementation of the GraphQL specification, designed for running GraphQL in a Node.js environment.
- Apollo Server: A set of GraphQL server packages from Apollo that work with various Node.js HTTP frameworks (Express, Connect, Hapi, Koa etc).
- GraphiQL: An interactive in-browser GraphQL IDE.
- GraphQL CLI: A command line tool for common GraphQL development workflows.