5. GET /user
POST /user
PUT /user
DELETE /user
GET /user/query..
Products
New resources needs to be added
Orders
Categories
…
Number of endpoints becomes really large, really fast
6. Resources needs to look different if we are dealing
with mobile or desktop
GET /users/1
data : {
firstname : ‘chris’,
}
GET /mobile/users/1
data : {
firstname : ‘chris’,
region : { url : ‘/regions/1’ }
}
Only the linkEagerly loaded
region : {
id : 1,
city : ‘Warsaw’,
country : ‘Poland’
}
7. Problem 2
Need for a unified way of asking for data
Twitter
Reddit
Github
Data Service
GraphQL
runtime
Frontend Query
9. Mismatch in response
Mapping is needed
{ “data” : {
“name”,
“address” : “Warsaw”
}
}
class Person {
surname: string;
city: string,
}
Need to rename to avoid remapping in Frontend
10. Might need several endpoints
class Person {
fname : string;
surname: string;
address: string,
friends : [],
records : []
}
Might lead to multiple requests
api/people/1
api/people/1/friends
api/people/1/records
12. GraphQL
Lets the client specify what they need,
“content negotiation”
Easier to aggregate data from many sources
Uses a type system to describe data
Application layer query language
Multiple resources in a single request
Open sourced by Facebook in 2015
24. A more advanced schema
var schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'world';
}
},
human : {
type : humanType,
resolve : () => getHuman()
}
}
})
});
function getHuman() {
return Promise.resolve(
return {
id : ‘1’,
description : ‘ a description’,
name : ‘john’
})
}
Our resolver should call
a db ideally
Resolver function
var humanType = new GraphQLObjectType({
name : 'Human',
fields : () => ({
id: { type: GraphQLString },
description : { type : GraphQLString },
name : { type : GraphQLString } }),
})
}
Complex type
var query = '{ human { name, description } }';
graphql(schema, query).then(result => {
// prints { data : { “human” : { “name” : “john”, “description” : “a description” } } }
console.log(result);
});
Do the query
25. Define and query a list type
var schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'world';
}
},
human : {
type : humanType,
resolve : () => getHuman()
},
humans : {
type : new GraphQLList(humanType),
resolve : () => getHumans()
}
}
})
});
var query = '{ humans { name, description } }';
graphql(schema, query).then(result => {
// prints { data : { “humans” : [
{ id: 1, name : ‘Luke’, description: ‘anakins son’ },
{ id: 2, name : ‘Vader’, description: ‘anakins?’},
{ id: 3, name : ‘Palpatine’, description: ‘anakins boss’ }] }
console.log(result);
});
Do the query
function getHumans() {
return Promise.resolve(
[{
id: 1, name : ‘Luke’, description: ‘anakins son’
},
{
id: 2, name : ‘Vader’, description: ‘anakins?’
},
{
id: 3, name : ‘Palpatine’, description: ‘anakins boss’
}]
)
}
26. Resolve dependencies part I
Imagine the following schema
humans : {
type: new GraphQLList(humanType),
resolve : (root, {}) => {
return getHumans();
}
}
getHumans() {
const humans = [
{id :'1', name: 'Luke', description: 'Anakins son', friends : ['2'] },
{id :'2', name: 'Darth', description: 'Anakin', friends : ['3'] },
{id :'3', name: 'Palpatine', description: 'Anakins master', friends : [] }
];
return Promise.resolve( humans );
}
How to resolve these
ids into objects?
27. var humanType = new GraphQLObjectType({
name : 'Human',
fields : () => ({
id: { type: GraphQLString },
description : { type : GraphQLString, description : 'desc' },
name : { type : GraphQLString, description : 'name of person' },
}),
interfaces : [ characterInterface ]
})
Resolve dependencies part II
Resolve
function getFriends(character) {
return character.friends.map( f => getHuman(f) );
}
Lookup by id
friends : {
type: new GraphQLList(humanType),
resolve : human => getFriends( human )
}
28. Query with an argument
human : {
type : humanType,
args : {
id: {
description: 'id of the jedi',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, { id }) => getHumanById(id)
}
resolve, we dig out the id
and use it to query our resolver
var query = '{ human(id: 1) { name, description } }';
graphql(schema, query).then(result => {
// prints { data : { “human( id: 1 )” : { “name” : “john”, “description” : “a description” } } }
console.log(result);
});
Do the query
Resolver
Define args
function getHumanById(id) {
let result = return Promise.resolve(
[{
id: 1, name : ‘Luke’, description: ‘anakins son’
},
{
id: 2, name : ‘Vader’, description: ‘anakins?’
},
{
id: 3, name : ‘Palpatine’, description: ‘anakins boss’
}].filter( h => h.id === id );
return result.length === 0 ? null : result[0];
)
}
30. Alias = rename field name in the query
query Test {
github {
userchris: user(username:"softchris") {
repos {
name
}
}
}
}
New value
Old value
“data” : {
“github” : {
“userchris” : {
“repos” : [{ “name” : “…”, … }]
}
}
}
32. Fragment is about cleaning up the code and make part of it
reusable
fragment UserDetail on GithubUser {
company: my_company,
avatar_url,
repos {
name,
commits {
message
}
}
}
query Github($user: String!, $repo: Boolean!) {
github {
user(username :$user) {
...UserDetail
}
}
}
We don’t need
to clutter the query
Update in one place when a field needs to be added
42. Inrementally adoptable
Universally compatible
Simple to get started with
Inspectable and understandable
Built for interactive apps
Small and flexible
Community driven
GraphQL Client with integrations to all major frameworks
43. Also get Chrome plugin
https://chrome.google.com/webstore/detail/apollo-client-
developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm/related
npm install apollo-client graphql-tag --save
Install
46. Links
graphql-express
Learn to build your own API
https://github.com/softchris/graphql-express-demo
Or cheat and check out my repo :)
http://graphql.org/learn/
Official documentation
47. Summing up
Is GraphQL replacing REST? You can use both actually
REST has many endpoints
and HATEOAS
GraphQL has one endpoint
and content negotiation
REST is an architecture
concept
GraphQL is query
language + tools
GraphQL only asks for fields
it need
REST responds with a
whole object