Build user interface centric API. Clients using GraphQL to construct design elements can efficiently fetch everything required for a component in one request.
/graphql
/posts
/posts/1
/posts/1/comments
/posts/1/comments/1
...
content-type: application/json
content-type: text/html
content-type: application/xhtml+xml
content-type: application/json
...
200 OK
400 Bad Request
200 OK
201 Created
202 Accepted
204 No Content
418 I'm a teapot
...
POST
GET
POST
PUT
PATCH
DELETE
...
GraphQL defines an API schema to organize available resources. Resources are declared using static types and connected to one another via fields.
{
"data": {
"authors": [{
"name": "Dat Boi",
"posts": [
{ "title": "Here he come" }
]
}
}]
}
{
"data": {
"createUser": {
"id": "3",
"email": "baz@example.com",
}
}
}
Builtin scalars
ID # A unique identifier
Int # A signed 32βbit integer.
Float # A signed double-precision floating-point value.
String # A UTFβ8 character sequence.
Boolean # `true` or `false`.
Custom scalars. Create any type you want
scalar Time
type Post {
time: Time
}
# Create parse and serialize handlers in your runtime.
TimeType = GraphQL::ScalarType.define do
name "Time"
description "Time since epoch in seconds"
coerce_input ->(value) { Time.at(Float(value)) }
coerce_result ->(value) { value.to_f }
end
# irb(main):001:0> Time.at(Float(1234567890))
# => 2009-02-13 17:31:30 -0600
Enum
# Enums are a collection of scalars referencing specific values
enum ExpenseType {
FOOD
TRAVEL
PARKING
}
type Query {
expenses(type: ExpenseType): [Expense]
}
%p Objects
enum CompanyType { CNN }
type Author {
name: String
posts: [Post]
}
type Post {
title: String
}
type Query {
bloggers(type: CompanyType): [Author]
}
Inputs
Define an explicit shape of all input objects for mutations. Save the work of manually parsing and validating the shape and size of user input. Let GraphQL do the grunt work!
Inputs
mutation createExpense($input: CreateExpenseInput!) {
createExpense(input: $input) {
id
}
}
input CreateExpenseInput {
type: ExpenseType!
amount: Float!
description: String
}
Modifiers
When reading data the GraphQL runtime responds with error messages communicating the state of the fulfilled query. Any non conformity to the schema is reported as an error.
Modifiers
! # Non null
[] # List
How it works
name: String # nullable name
name: String! # non nullable name
names: [String] # nullable list of nullable names
names: [String]! # non nullable list of nullable names
names: [String!]! # non nullable list of non nullable names
Modifiers on types
{
"errors": [
{ "message": "Cannot return null for non-nullable field User.name.", }
],
"data": {
"user": null
}
}
Modifiers on arguments
{
"errors": [
{
"message": "Field \"viewer\" argument \"id\" of type \"ID!\" is required but not provided.",
}
]
}
Modifiers on inputs π
{
"errors": [
{
"message": "Field CreateUserInput.email of required type String! was not provided.",
}
]
}
Unions
A set of possible types with no guarantee of consistency between fields.
Unions
type SocialMediaPost {
content: String
}
type BlogPost {
title: String
content: String
}
union PostUnion = BlogPost | SocialMediaPost
type Query {
posts: [PostUnion]
}
Unions
Interface
An abstract type declaring common fields and arguments. Any object implementing an interface is guarantees certain fields exist.
Interface
interface MutationResult {
notice: String
success: Boolean!
}
type CreateExpensePayload implements MutationResult {
result: Expense
success: Boolean!
}
mutation {
createExpense(input: CreateExpenseInput!): CreateExpensePayload
}
Interface
GraphQL is a runtime layer between the client and your business logic. It is responsible for analyzing, validating, and resolving incoming requests. GraphQL implementations currently exist for: C# / .NET, Clojure, Elixir, Erlang, Go, Groovy, Java, JavaScript, PHP, Python, Scala, Ruby
Queries can become complex and tax your system of resources π«. The runtime performs complexity and depth analysis on all incoming requests, and if you wish, it can only allow queries within a specific threshold.
MySchema = GraphQL::Schema.define do
max_depth 10 # Prevent deeply nested resources
max_complexity 100 # Reject complex queries
end
query {
user {
juicyBitcoins
}
}
{
"errors": [
{
"message": "Cannot query field \"juicyBitcoins\" on type \"User\".",
"locations": [
{
"line": 3,
"column": 5
}
]
}
]
}
The runtime resolves fields. By default, fields are resolved from the underlying struct and the values are returned for the field.
Resolvers are anonymous functions called with three arguments
query {
currentUser {
email
}
}
const resolvers = {
Query: {
currentUser: (object, args, context) => context.currentUser
}
}
// object # In memory object (think ORM)
// args # GQL query arguments
// context # Global state
Define resolvers inline, if you want.
const resolvers = {
User: {
emailAddressLength: object => object.email.length,
randomFloat: () => Math.random()
}
}
Add descriptions. Deprecate fields. Communicate.
Add descriptions. Deprecate fields. Communicate.
Add descriptions. Deprecate fields. Communicate.
Add descriptions. Deprecate fields. Communicate.
Add descriptions. Deprecate fields. Communicate. Some good examples:
Push input paramater validations out into the GraphQL runtime and build user interfaces to consume and bubble up responses.
Design components that speak GraphQL and only request data required to render the component
const query = gql`
query {
greeting
}
`
const Greeter = props => (
<div>
<h1> {props.data.greeting} </h1>
</div>
)
export default graphql(query)(Greeter);
See Apollo GraphQL for more information
Present N distinct GraphQL APIs into a single schema with a concept known as schema stitching.
See Schema stitching for more information. Example
The GraphQL runtime provides executions hooks into each of your resolvers. It is possible to know the time it takes to resolve each field.