GraphQL
Towards a Universal Query Language
GraphQL
The plan
G’day, how’s it goin’?
👋
Schema Definition Language
type Conference {
id: Int!
name: String!
speakers: [Speaker!]
}
type Speaker {
id: Int!
name: String!
emoji: String!
conference: [Conference!]�}
type Query {
conferences(): [Conference!]
speakers(emoji: String!): [Speaker!]
}
type Mutation {
speak(speakerID: Int, conferenceID: Int): [Conference!]�}
Resolvers
function resolver(parent, args, context) {
};
const resolvers = {
Query: {
speakers(parent, args, context) {
return [
{ id: 15, name: "Una Kravets", emoji: "🦄" },
{ id: 37, name: "Michael Mifsud", emoji: "🍕" }
]
.filter(speaker => speaker.emoji === args.emoji)
}
}�};
const resolvers = {
Query: { ... },
Mutation: {
speak(parent, args, context) {
const conferences = context.conferences;
return conferences.loadById(args.conferenceID)
.then(c => c.addSpeaker(speakerID))
.then(c => s.save())
.then(c => conferences.loadBySpeaker(args.speakerID))
}
}
};
Resolvers for profit
const resolvers = {
Query: {
speakers() {
return [
{ id: 1, name: "Una Kravets", emoji: "🦄" },
{ id: 2, name: "Michael Mifsud", emoji: "🍕" }
]
}
}
};
The default resolver
const resolver = (parent, args, context) => {
return typeof parent[field] === "function"
? parent[field](args)
: parent[field];�};
const resolvers = {
Query: { ... },
Speaker: {
id(parent) => parent.id,
name(parent) => parent.name,
emoji(parent) => parent.emoji,
conference(parent) => parent.conferences,
}
};
APIs
const resolvers = {
Query: {
speakers(parent, args, context) {
return jQuery.ajax({
url: `https://speakers.io/${args.emoji}`,
headers: {
'Content-Type': 'application/json',
'X-API-KEY': context.secrets.apiKey,
}
});
}
}
};
const resolvers = {
Query: { ... },
Speaker: {
conferences(parent, args, context) {
return fetch(`https://conferences.io/${parent.id}`, {
headers: {
'Content-Type': 'application/json',
'X-API-KEY': context.secrets.apiKey
}
})
.then((resp) => resp.json())
}
}�};
{
speakers(emoji: "🍕") {
name
conferences {
name
}
}�}
{
"speakers": [{
"name": "Michael Mifsud",
"conferences": [{
"name": "JSConf EU"
}]
}]�}
Databases
const resolvers = {
Query: {
speakers(parent, args, context) {
return context.db.loadSpeakerByEmoji(args.emoji);
}
}�};
Datastores
const resolvers = {
Query: {
speakers(parent, args, context) {
return context.db.loadSpeakerByEmoji(args.emoji);
}
},
Speaker: {
conferences(parent, args, context) {
return context.elasticSearch.execute(...);
},
emoji(parent, args, context) {
return context.redis.get(...);
}
}
};
The file system
Spreadsheets!
const resolvers = {
Query: {
speakers(parent, args, context) {
return fs.promises.readFile('speakers.csv')
.then(context.csv.parse)
.then(data => data.filter(({ emoji }) => {
return emoji === args.emoji;
}));
}
}�};
Javascript APIs
const resolvers = {
Query: {
configuration(parent, args, context) {
return fs.promises.readFile(`config/${args.type}.json`)
}
}�};
{
configuration(type: "keys") {
speakerAPIKey
conferenceAPIKey
databaseURN
}�}
GraphQL
server.on('request', (req) => {
const client = new GraphQLServer({
schema,
resolvers,
context: { configuration: getConfiguration() },
});
client.handle(req);
});
✋🎤
Everything is a GraphQL
Resolvers for fun
Don’t try this at home
GraphQL in the browser
But why?
Datastore
const store = require('store');
const resolvers = {
Query: {
speakers(parent, args, context) {
return store.get('speakers')
.then(data => data.filter(({ emoji }) => {
return emoji === args.emoji;
}));
}
}�};
APIs
const resolvers = {
Query: {
speakers(parent, args, context) {
return fetch ? fetch(...) : new XMLHttpRequest(...)
}
}�};
GraphQL in the browser
The DOM
type Query {
document: Document
}
type Document {
querySelector: Element
querySelectorAll: NodeList
}
type Element {
tagName: String!
}��type NodeList { ... }
const resolvers = {
Query: {
document() { return window.document }
},
Document: {
querySelector(parent, args, context) {
return parent.querySelector(args.selectors);
}
},
Element: {
tagName(parent, args, context) {
return parent.tagName;
}
}
};
const speakers = client.query(`{
window {
fetch(url: "https://speakers.io/🇩🇪") {
json
}
}
}`);
const tagName = client.query(`{
document {
querySelectorAll(selectors: "body") {
tagName
}
}
}`);
const conference = client.query(`{
fs {
readFile(path: "conferences.csv") {
csv
}
}
}`);
type Query {
document: Document
}
type Document {
querySelector: Element
querySelectorAll: NodeList
}
type Element {
tagName: String!
}��type NodeList { ... }
Mo schema, mo problems
const resolver = (parent, args, context) => {
return typeof parent[field] === "function"
? parent[field](args)
: parent[field];�};
const resolvers = {
Query: {
document() { return window.document }
},
Document: {
querySelector(parent, args, context) {
return parent.querySelector(args.selectors);
}
},
Element: {
tagName(parent, args, context) {
return parent.tagName;
}
}
};
In closing
Thank you