GraphQL

GraphQL
A data query language and runtime
GraphQL
- Declarative
- Compositional
- Strong-typed
DECLARATIVE
- query responses decided by the client
- query returns exactly what a client asks for
COMPOSITIONAL
- query is a hierarchical set of fields
- query is shaped just like the data it returns
- natural way to describe data requirements
STRONG-TYPED
- query can be ensured to be valid within
a GraphQL type system at development time - this allows the server to make guarantees about the response
- makes it easier to build high-quality client tools
"OK, but why?"
REST API
- easy resource access and management
- resource relationships
- shallow resources - multiple requests
- nested resources - expensive support
GraphQL
- ask for all data you need in query
- send query to single endpoint
- receive all data in one response
- to modify data call mutations
Play time!
{
}empty query
{
posts {
title
}
}posts query (titles)
{
posts {
title,
_id,
summary
}
}posts query (title, id, summary)
{
posts {
title,
_id,
summary
},
authors {
name
}
}posts query and authors query
{
posts {
_id,
title,
timestamp,
summary
}
posts {
_id,
title,
content,
category
}
}
different results for same schema
{
postsShort: posts {
_id,
title,
timestamp,
summary
}
postsFull: posts {
_id,
title,
content,
category
}
}
{
author(_id: "indi"){
_id,
name
}
recentPosts(count: 5) {
title,
summary,
timestamp
}
}
query with params
named query results
{
currentAuthor: author(_id: "indi"){
_id,
name
}
currentPosts: recentPosts(count: 5) {
title,
summary,
timestamp
}
allPosts: posts {
title,
content,
summary
}
}
Single entries
{
indi: author(_id: "indi"){
_id,
name,
twitterHandle
}
arunoda: author(_id: "arunoda"){
_id,
name,
twitterHandle
}
pahan: author(_id: "pahan"){
_id,
name,
twitterHandle
}
}Nested queries
{
posts {
title,
_id,
author {
name
}
}
}{
posts {
title,
_id,
comments {
_id,
content
}
}
}{
posts {
title,
_id,
comments {
_id,
content
},
author {
_id,
name
}
}
}{
posts {
title,
_id,
comments {
_id,
content,
author {
_id,
name
}
}
}
}{
posts {
title,
_id,
comments {
_id,
content,
author {
_id,
name
}
},
author {
_id,
name
}
}
}Repetitive queries - use fragments
{
indi: author(_id: "indi"){
_id,
name,
twitterHandle
}
arunoda: author(_id: "arunoda"){
_id,
name,
twitterHandle
}
pahan: author(_id: "pahan"){
_id,
name,
twitterHandle
}
}{
indi: author(_id: "indi"){
...authorData
}
arunoda: author(_id: "arunoda"){
...authorData
}
pahan: author(_id: "pahan"){
...authorData
}
}
fragment authorData on Author {
_id,
name,
twitterHandle
}Repetitive queries - use fragments
{
posts {
title,
_id,
comments {
_id,
content,
author {
_id,
name
}
},
author {
_id,
name
}
}
}{
posts {
title,
_id,
comments {
_id,
content,
author {
...authorName
}
},
author {
...authorName
}
}
}
fragment authorName on Author {
_id,
name
}Repetitive queries - use fragments and interfaces
{
posts {
title,
_id,
comments {
_id,
content,
author {
_id,
name
}
},
author {
_id,
name
}
}
}{
posts {
title,
_id,
comments {
_id,
content,
...authorOf
},
...authorOf
}
}
fragment authorOf on HasAuthor {
author {
_id,
name,
}
}{
posts {
title,
_id,
comments {
_id,
content,
author {
...authorName
}
},
author {
...authorName
}
}
}
fragment authorName on Author {
_id,
name
}Change data - Mutations
mutation {
createAuthor(
_id: "john",
name: "John Carter",
twitterHandle: "@john"
) {
_id
name
}
}mutation {
sam: createAuthor(
_id: "sam",
name: "Sam Hautom"
twitterHandle: "@sam"
) {
_id
name
},
chris: createAuthor(
_id: "chris",
name: "Chris Mather"
twitterHandle: "@chris"
) {
_id
name
}
}Change data - Mutations
mutation {
carter: createAuthor(
_id: "carter",
name: "Carter Boom"
twitterHandle: "@carter"
) {
_id
},
carter2: createAuthor(
_id: "carter",
name: "Carter Boom"
twitterHandle: "@carter"
) {
_id
}
}- queries are concurrent
- mutations are sequential!
Query Variables
{
recentPosts(count: 10) {
title
}
}for hard-coded values
query getFewPosts {
recentPosts(count: 10) {
title
}
}full query syntax (with query name)
query getFewPosts($postCount: Int!) {
recentPosts(count: $postCount) {
title
}
}query with declared variable
Query Variables
multiple variables
query getFewPosts($postCount: Int!, $commentCount: Int) {
recentPosts(count: $postCount) {
title,
comments(limit: $commentCount) {
content
}
}
}query getFewPosts($postCount: Int!, $commentCount: Int) {
recentPosts(count: $postCount) {
title,
...comments
}
}
fragment comments on Post {
comments(limit: $commentCount) {
content
}
}variables in fragments
So, where that query goes?
You can send GraphQL queries through HTTP:
- GET for querying
- POST for mutation
GraphQL
- "API pattern"
- query language
- specification
- reference implementations
Implementations
- PHP
- Ruby
- Python
- C / C++
- Scala
- Elixir
- Go
- .NET
- Haskell
- JavaScript
TODO:
- define graph of "resources"
- send query to single endpoint
- receive all data in one response
What about client?
- send query string & get JSON data
- use Relay
- use Lokka
- more clients soon
Risks
- caching
- N + 1 problem hard to detect
- abusive
GraphQL
By Krzysztof Jung
GraphQL
- 1,258