Lead Sr. Software Engineer at Double
Big fan and user of GraphQL since 4 years
{
project(name: "GraphQL") {
tagline
}
}
{
"project": {
"tagline": "A query language for APIs"
}
}
type Project {
name: String
tagline: String
contributors: [User]
}
type Query {
project(name: String!): Project
}
const resolvers = {
Query: {
project: (parent, args, context, info) => (
projects.find(p => p.name === args.name)
),
},
};
1. Schema
2. Resolvers
3. Query
4. JSON data
server: graphql@0.0.2 (+ express)
client: relay@0.1.0
server: graphql@0.0.2 (+ express)
import {
graphql,
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
} from 'graphql';
var schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'world';
},
},
},
}),
});
graphql-tools
apollo-server
apollo-client (+ react-apollo)
graphiql
Libraries to boost development
graphql-tools
import { makeExecutableSchema } from '@graphql-tools/schema';
const resolvers = /*...*/
const typeDefs = `
# ...
schema {
query: Query
mutation: Mutation
}
`;
const executableSchema = makeExecutableSchema({
typeDefs,
resolvers,
});
Libraries: Apollo, Relay
Concepts: Schema stitching, client cache, optimistic UI patterns
Services: AWS App Sync, Apollo Optics, Prisma
Faster and more robust development
Apollo Federation
Hasura
GraphQL Mesh
Prisma
GraphQL Engine
Apollo State management
DGraph
TypeGraphQL
graphqless
GraphCMS
Gatsby
AWS AppSync
Relay
Hasura
GraphQL Code Generator
GraphQL modules
Apollo Platform
urql
GraphQL is much more than an efficient way of fetching data from the client side
GraphQL is much more than an efficient way of fetching data from the client side
GraphQL is a "data query and manipulation language for APIs"
Local state management with GraphQL
import { TypePolicies, makeVar } from '@apollo/client';
export const DARK_MODE_KEY = 'dark-mode'
export const darkMode = makeVar<boolean>(localStorage.getItem(DARK_MODE_KEY) || false)
export const resolvers: TypePolicies = {
Query: {
fields: {
darkMode: {
read: () => darkMode(),
},
},
},
};
export default resolvers
const { data } = useQuery(`
query isDarkMode {
darkMode @client
}
`)
import { TypePolicies, makeVar } from '@apollo/client';
export const DARK_MODE_KEY = 'dark-mode'
export const darkMode = makeVar<boolean>(localStorage.getItem(DARK_MODE_KEY) || false)
export const resolvers: TypePolicies = {
Query: {
fields: {
darkMode: {
read: () => darkMode(),
},
},
},
};
export default resolvers
darkMode(true)
updates
useQuery() hook
import { darkMode, DARK_MODE_KEY } from './resolvers'
const useUpdateDarkMode = () => useCallback(
(enabled: boolean) => {
localStorage.setItem(DARK_MODE_KEY, enabled)
darkMode(enabled)
},
[],
)
export default useUpdateDarkMode
const { data, error } = useMainTopicListQuery()
// data contains remote + local todos
Apollo Cache
TypePolicies read()
functions
useQuery() hooks
const { data } = useQuery(`
query getMainTopicList($completedAfter: DateTime!) {
activeTopics: topicsList(first: 200, view: ACTIVE) {
hasAfter
items {
...TopicListItem
}
}
}
`)
const typePolicies: TypePolicies = {
Query: {
fields: {
topicsList: {
keyArgs: ['view', 'first'],
// ...
read: (existing, { args }) => {
const draft = todoDrafts()
return draft ?
{
...existing,
items: [
draft,
...(existing ? existing.items : []),
],
}:
existing
},
},
},
},
}
fragment TodoListItem on Todo {
id
reference
title
# ...
isDraft @client
# ...
}
export const resolvers: TypePolicies = {
// we augment the `Todo` type
Todo: {
fields: {
isDraft: {
read: (existing = false, { readField }) => isDraft(readField('id')),
},
},
},
};
GraphQL introspection is a core
- most underrated - feature of the language
{
__schema {
types {
name
kind
fields {
name
type {
name
ofType {
name
}
}
}
}
}
}
{
"data": {
"__schema": {
"types": [
{
"name": "Query",
/* ... */
},
{
"name": "PrivateUser",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "birthday",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "country",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "display_name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "email",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "product",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "tracks",
"type": {
"name": null,
"ofType": {
"name": "SavedTrack"
}
}
},
{
"name": "playlists",
"type": {
"name": null,
"ofType": {
"name": "Playlist"
}
}
},
{
"name": "albums",
"type": {
"name": null,
"ofType": {
"name": "SavedAlbum"
}
}
},
{
"name": "top_artists",
"type": {
"name": null,
"ofType": {
"name": "Artist"
}
}
},
{
"name": "top_tracks",
"type": {
"name": null,
"ofType": {
"name": "Track"
}
}
},
{
"name": "images",
"type": {
"name": null,
"ofType": {
"name": "Image"
}
}
},
{
"name": "artists",
"type": {
"name": null,
"ofType": {
"name": "Artist"
}
}
},
{
"name": "devices",
"type": {
"name": null,
"ofType": {
"name": "Device"
}
}
},
{
"name": "player",
"type": {
"name": "Player",
"ofType": null
}
}
]
},
{
"name": "String",
"kind": "SCALAR",
"fields": null
},
{
"name": "Int",
"kind": "SCALAR",
"fields": null
},
{
"name": "SavedTrack",
"kind": "OBJECT",
"fields": [
{
"name": "added_at",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "track",
"type": {
"name": "Track",
"ofType": null
}
}
]
},
{
"name": "Track",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "album",
"type": {
"name": "Album",
"ofType": null
}
},
{
"name": "artists",
"type": {
"name": null,
"ofType": {
"name": "Artist"
}
}
},
{
"name": "available_markets",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "audio_features",
"type": {
"name": "AudioFeatures",
"ofType": null
}
},
{
"name": "disc_number",
"type": {
"name": "Int",
"ofType": null
}
},
{
"name": "duration_ms",
"type": {
"name": "Int",
"ofType": null
}
},
{
"name": "explicit",
"type": {
"name": "Boolean",
"ofType": null
}
},
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "is_playable",
"type": {
"name": "Boolean",
"ofType": null
}
},
{
"name": "name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "popularity",
"type": {
"name": "Int",
"ofType": null
}
},
{
"name": "preview_url",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "track_number",
"type": {
"name": "Int",
"ofType": null
}
},
{
"name": "type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
}
]
},
{
"name": "Album",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "album_type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "artists",
"type": {
"name": null,
"ofType": {
"name": "Artist"
}
}
},
{
"name": "available_markets",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "genres",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "label",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "popularity",
"type": {
"name": "Int",
"ofType": null
}
},
{
"name": "release_date",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "release_date_precision",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "images",
"type": {
"name": null,
"ofType": {
"name": "Image"
}
}
},
{
"name": "tracks",
"type": {
"name": null,
"ofType": {
"name": "Track"
}
}
}
]
},
{
"name": "Artist",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "genres",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "popularity",
"type": {
"name": "Int",
"ofType": null
}
},
{
"name": "type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "images",
"type": {
"name": null,
"ofType": {
"name": "Image"
}
}
},
{
"name": "top_tracks",
"type": {
"name": null,
"ofType": {
"name": "Track"
}
}
},
{
"name": "albums",
"type": {
"name": null,
"ofType": {
"name": "Album"
}
}
},
{
"name": "related_artists",
"type": {
"name": null,
"ofType": {
"name": "Artist"
}
}
}
]
},
{
"name": "Image",
"kind": "OBJECT",
"fields": [
{
"name": "height",
"type": {
"name": "Int",
"ofType": null
}
},
{
"name": "url",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "width",
"type": {
"name": "Int",
"ofType": null
}
}
]
},
{
"name": "AudioFeatures",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "acousticness",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "analysis_url",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "danceability",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "duration_ms",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "energy",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "instrumentalness",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "key",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "liveness",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "loudness",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "mode",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "speechiness",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "tempo",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "time_signature",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "track_href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "valence",
"type": {
"name": "String",
"ofType": null
}
}
]
},
{
"name": "Boolean",
"kind": "SCALAR",
"fields": null
},
{
"name": "Playlist",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "description",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "owner",
"type": {
"name": "PublicUser",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "tracks",
"type": {
"name": null,
"ofType": {
"name": "PlaylistTrack"
}
}
},
{
"name": "public",
"type": {
"name": "Boolean",
"ofType": null
}
},
{
"name": "images",
"type": {
"name": null,
"ofType": {
"name": "Image"
}
}
}
]
},
{
"name": "PublicUser",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "display_name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "playlists",
"type": {
"name": null,
"ofType": {
"name": "Playlist"
}
}
},
{
"name": "images",
"type": {
"name": null,
"ofType": {
"name": "Image"
}
}
}
]
},
{
"name": "PlaylistTrack",
"kind": "OBJECT",
"fields": [
{
"name": "added_at",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "track",
"type": {
"name": "Track",
"ofType": null
}
},
{
"name": "added_by",
"type": {
"name": "PublicUser",
"ofType": null
}
},
{
"name": "is_local",
"type": {
"name": "Boolean",
"ofType": null
}
}
]
},
{
"name": "SavedAlbum",
"kind": "OBJECT",
"fields": [
{
"name": "added_at",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "album",
"type": {
"name": "Album",
"ofType": null
}
}
]
},
{
"name": "Device",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "is_active",
"type": {
"name": "Boolean",
"ofType": null
}
},
{
"name": "is_restricted",
"type": {
"name": "Boolean",
"ofType": null
}
},
{
"name": "name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "volume_percent",
"type": {
"name": "Int",
"ofType": null
}
}
]
},
{
"name": "Player",
"kind": "OBJECT",
"fields": [
{
"name": "timestamp",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "device",
"type": {
"name": "Device",
"ofType": null
}
},
{
"name": "progress_ms",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "is_playing",
"type": {
"name": "Boolean",
"ofType": null
}
},
{
"name": "shuffle_state",
"type": {
"name": "Boolean",
"ofType": null
}
},
{
"name": "repeat_state",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "item",
"type": {
"name": "Track",
"ofType": null
}
},
{
"name": "context",
"type": {
"name": "PlayerContext",
"ofType": null
}
}
]
},
{
"name": "PlayerContext",
"kind": "OBJECT",
"fields": [
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
}
]
},
{
"name": "__Schema",
"kind": "OBJECT",
"fields": [
{
"name": "types",
"type": {
"name": null,
"ofType": {
"name": null
}
}
},
{
"name": "queryType",
"type": {
"name": null,
"ofType": {
"name": "__Type"
}
}
},
{
"name": "mutationType",
"type": {
"name": "__Type",
"ofType": null
}
},
{
"name": "subscriptionType",
"type": {
"name": "__Type",
"ofType": null
}
},
{
"name": "directives",
"type": {
"name": null,
"ofType": {
"name": null
}
}
}
]
},
{
"name": "__Type",
"kind": "OBJECT",
"fields": [
{
"name": "kind",
"type": {
"name": null,
"ofType": {
"name": "__TypeKind"
}
}
},
{
"name": "name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "description",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "fields",
"type": {
"name": null,
"ofType": {
"name": null
}
}
},
{
"name": "interfaces",
"type": {
"name": null,
"ofType": {
"name": null
}
}
},
{
"name": "possibleTypes",
"type": {
"name": null,
"ofType": {
"name": null
}
}
},
{
"name": "enumValues",
"type": {
"name": null,
"ofType": {
"name": null
}
}
},
{
"name": "inputFields",
"type": {
"name": null,
"ofType": {
"name": null
}
}
},
{
"name": "ofType",
"type": {
"name": "__Type",
"ofType": null
}
}
]
},
{
"name": "__TypeKind",
"kind": "ENUM",
"fields": null
},
{
"name": "__Field",
"kind": "OBJECT",
"fields": [
{
"name": "name",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "description",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "args",
"type": {
"name": null,
"ofType": {
"name": null
}
}
},
{
"name": "type",
"type": {
"name": null,
"ofType": {
"name": "__Type"
}
}
},
{
"name": "isDeprecated",
"type": {
"name": null,
"ofType": {
"name": "Boolean"
}
}
},
{
"name": "deprecationReason",
"type": {
"name": "String",
"ofType": null
}
}
]
},
{
"name": "__InputValue",
"kind": "OBJECT",
"fields": [
{
"name": "name",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "description",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "type",
"type": {
"name": null,
"ofType": {
"name": "__Type"
}
}
},
{
"name": "defaultValue",
"type": {
"name": "String",
"ofType": null
}
}
]
},
{
"name": "__EnumValue",
"kind": "OBJECT",
"fields": [
{
"name": "name",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "description",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "isDeprecated",
"type": {
"name": null,
"ofType": {
"name": "Boolean"
}
}
},
{
"name": "deprecationReason",
"type": {
"name": "String",
"ofType": null
}
}
]
},
{
"name": "__Directive",
"kind": "OBJECT",
"fields": [
{
"name": "name",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "description",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "locations",
"type": {
"name": null,
"ofType": {
"name": null
}
}
},
{
"name": "args",
"type": {
"name": null,
"ofType": {
"name": null
}
}
}
]
},
{
"name": "__DirectiveLocation",
"kind": "ENUM",
"fields": null
},
{
"name": "SimplifiedArtist",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
}
]
},
{
"name": "SimplifiedAlbum",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "album_type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "artists",
"type": {
"name": null,
"ofType": {
"name": "Artist"
}
}
},
{
"name": "available_markets",
"type": {
"name": null,
"ofType": {
"name": "String"
}
}
},
{
"name": "href",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "label",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "name",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "type",
"type": {
"name": "String",
"ofType": null
}
},
{
"name": "uri",
"type": {
"name": "String",
"ofType": null
}
}
]
}
]
}
}
}
Given a GraphQL Schema, generates:
We now have 'cheap to maintain'
best-in-class TypeScript types in our front-end
const User = graphql(({ user }: { user: User }) => (
<div>
<h2>{user.name}</h2>
<img src={user.avatarUrl({ size: 100 })} />
</div>
))
const App = graphql(() => (
<div>
{query.users.map(user => (
<User key={user.id} user={user} />
))}
</div>
))
query App {
users {
id
name
avatarUrl(size: 100)
}
}
+ TypeScript support
import gql from "graphql-tag";
import { Frontier } from "frontier-forms";
import { myApplicationKit } from "./uiKit";
import { client } from "./apollo-client";
const mutation = gql`
mutation($user: User!) {
createUser(user: $user) { id }
}
`;
<Frontier
client={client}
mutation={mutation}
uiKit={myApplicationKit}
/>
Hasura translate GraphQL AST to SQL AST,
providing blazing fast execution with minimum configuration
Custom logic support via Actions
GraphQL Mesh leverages API definition standards to transform existing API to GraphQL APIs
Spotify GraphQL in 5'
Spotify GraphQL in 5'
Spotify GraphQL in 5'
GraphQL Mesh doesn’t aim to create [...] public GraphQL schema [...], you should consider implementing another layer that exposes your public data [...].