GraphQL in 2020
GraphQL in 2020
Who am I
Lead Sr. Software Engineer at Double
Big fan and user of GraphQL since 4 years
Charly POLY
GraphQL in 2020
GraphQL in 1'
{
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
GraphQL in 2020
GraphQL in 2015
initial public release
server: graphql@0.0.2 (+ express)
client: relay@0.1.0
GraphQL in 2020
GraphQL in 2015
initial public release
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 in 2020
GraphQL in 2016
Ecosystem awakening
graphql-tools
apollo-server
apollo-client (+ react-apollo)
graphiql
Libraries to boost development
GraphQL in 2020
GraphQL in 2016
Ecosystem awakening
graphql-tools
import { makeExecutableSchema } from '@graphql-tools/schema';
const resolvers = /*...*/
const typeDefs = `
# ...
schema {
query: Query
mutation: Mutation
}
`;
const executableSchema = makeExecutableSchema({
typeDefs,
resolvers,
});
GraphQL in 2020
GraphQL in 2016 - intermission
GraphQL in 2020
GraphQL in 2018 - intermission
GraphQL in 2020
GraphQL in 2018 - intermission
-
Build smooth user-experiences
"Ask for what you want", optimistic UIs
-
Solve data-complexity issue on front-end side
Apollo cache, typed mutations, DDD APIs
-
Microservices orchestration
Apollo schema stitching ➡️ Apollo Federation
GraphQL in 2020
GraphQL in 2018
Ecosystem on the rise
Libraries: Apollo, Relay
Concepts: Schema stitching, client cache, optimistic UI patterns
Services: AWS App Sync, Apollo Optics, Prisma
Faster and more robust development
GraphQL in 2020
GraphQL in 2018
First public GraphQL APIs
GraphQL in 2020
GraphQL in 2019
State of JS 2019
GraphQL in 2020
GraphQL in 2020?
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 in 2020
GraphQL in 2020
GraphQL is much more than an efficient way of fetching data from the client side
GraphQL in 2020
GraphQL in 2020
GraphQL is much more than an efficient way of fetching data from the client side
1. The GraphQL innovations on front-end side
2. GraphQL bridging the gaps on server-side
The GraphQL innovations on front-end side
GraphQL as state management
GraphQL in 2020
GraphQL as state management
Recoil
GraphQL in 2020
GraphQL as state management
GraphQL is a "data query and manipulation language for APIs"
GraphQL in 2020
GraphQL as state management
- Apollo Client 1 & 2: build the best GraphQL Client
- Apollo Client 3: a library for interacting with a client-side data graph
Apollo Client mission
Local state management with GraphQL
GraphQL in 2020
GraphQL as state management
Simple local state example
GraphQL in 2020
GraphQL as state management
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
}
`)
Example: darkMode settings
GraphQL in 2020
GraphQL as state management
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
Example: darkMode settings
GraphQL in 2020
GraphQL as state management
import { darkMode, DARK_MODE_KEY } from './resolvers'
const useUpdateDarkMode = () => useCallback(
(enabled: boolean) => {
localStorage.setItem(DARK_MODE_KEY, enabled)
darkMode(enabled)
},
[],
)
export default useUpdateDarkMode
Example: darkMode settings
GraphQL in 2020
GraphQL as state management
More advanced local state example
GraphQL in 2020
GraphQL as state management
- TodoList items are remote (GQL API)
- The newly created Todo is local
- Totally transparent at component- level
const { data, error } = useMainTopicListQuery()
// data contains remote + local todos
GraphQL in 2020
GraphQL as state management
Adding the TodoDraft to the list Query
Apollo Cache
TypePolicies read()
functions
useQuery() hooks
GraphQL in 2020
GraphQL as state management
1. Adding the TodoDraft to the list Query
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
},
},
},
},
}
GraphQL in 2020
GraphQL as state management
2. Todo `isDraft` local property
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 in 2020
GraphQL as state management
GraphQL in 2020
GraphQL as state management
Full local state management capabilities
- State: managed by ApolloCache, along side with APIs data
- Computed values: TypePolicies
- Actions: reactive variables or client.writeQuery()
- Reactions: Apollo ObservableQuery + reactive variables
- Tools: Apollo Client Dev tools
The GraphQL innovations on front-end side
GraphQL Full-stack type safety
GraphQL in 2020
GraphQL Full-stack type safety
GraphQL introspection is a core
- most underrated - feature of the language
GraphQL in 2020
GraphQL Full-stack type safety
{
__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
}
}
]
}
]
}
}
}
GraphQL in 2020
GraphQL Full-stack type safety
GraphQL in 2020
GraphQL Full-stack type safety
Given a GraphQL Schema, generates:
- TypeScript types definition
- React Apollo hooks definition
- urql components
- Types for Flow, Java, Kotlin
GraphQL in 2020
GraphQL Full-stack type safety
Typed React hooks generations
GraphQL in 2020
GraphQL Full-stack type safety
`TypedDocumentNode` for simplicity
GraphQL in 2020
GraphQL Full-stack type safety
We now have 'cheap to maintain'
best-in-class TypeScript types in our front-end
GraphQL in 2020
GraphQL (Beyond type safety intermission)
GraphQL in 2020
GraphQL (Beyond type safety intermission)
Better front-end developer experience
-
GraphQL without queries
-
GraphQL forms
GraphQL in 2020
GraphQL (Beyond type safety intermission)
GraphQL without queries: gqless
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
GraphQL in 2020
GraphQL (Beyond type safety intermission)
GraphQL forms: Frontier
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}
/>
GraphQL bridging the gaps on server-side
GraphQL in 2020
GraphQL bridging the gaps on server-side
Apollo
Prisma
AWS AppSync
GraphQL in 2020
GraphQL bridging the gaps on server-side
Apollo
Prisma
- What about more complex GraphQL APIs without a from-scratch development?
GraphQL in 2020
GraphQL bridging the gaps on server-side
Apollo
Prisma
Hasura
GraphQL in 2020
GraphQL bridging the gaps on server-side
Hasura
Hasura translate GraphQL AST to SQL AST,
providing blazing fast execution with minimum configuration
GraphQL in 2020
GraphQL bridging the gaps on server-side
Hasura
Custom logic support via Actions
GraphQL in 2020
GraphQL bridging the gaps on server-side
Hasura
- ACL support
- Authentication / Authorization (JWT)
- Remote schemas support (schema stitching)
- Subscriptions support
- Actions for custom logic
- Trigger webhooks on database events
- Bonus: one-click install on most cloud providers
GraphQL in 2020
GraphQL bridging the gaps on server-side
Apollo
Prisma
- What about old REST APIs and external services?
GraphQL in 2020
GraphQL bridging the gaps on server-side
Apollo
Prisma
GraphQL Mesh
GraphQL in 2020
GraphQL Mesh
GraphQL bridging the gaps on server-side
GraphQL Mesh leverages API definition standards to transform existing API to GraphQL APIs
GraphQL in 2020
GraphQL Mesh
GraphQL bridging the gaps on server-side
Spotify GraphQL in 5'
GraphQL in 2020
GraphQL Mesh
GraphQL bridging the gaps on server-side
Spotify GraphQL in 5'
GraphQL in 2020
GraphQL Mesh
GraphQL bridging the gaps on server-side
Spotify GraphQL in 5'
GraphQL in 2020
GraphQL Mesh
GraphQL bridging the gaps on server-side
- GraphQL proxy over your data
- Schema transformation
- Resolvers composition
- Caching
- SDK generation
GraphQL Mesh doesn’t aim to create [...] public GraphQL schema [...], you should consider implementing another layer that exposes your public data [...].
GraphQL in 2020
GraphQL API building in 2020
- Apollo, Prisma, and AWS AppSync are not unique solutions
- Hasura helps you build performant and powerful API
- GraphQL Mesh brings you universal GraphQL
GraphQL bridging the gaps on server-side
GraphQL in 2020
GraphQL in 2020 ⚡️
Wrap-up
GraphQL in 2020
GraphQL in 2020 ⚡️
- The Guild
- Hasura
- Dgraph
- and many more individual contributors!
Beyond a "Facebook & Apollo technology"
GraphQL in 2020
GraphQL in 2020 ⚡️
- Better front-end developer experience (Full-stack type safety, ...)
- Easier complex GraphQL API building (Hasura)
- Fast GraphQL Database (Dgraph, Hasura)
- GraphQL as a universal data language (state, GraphQL Mesh)
Beyond fetching data from the client-side
GraphQL in 2020
GraphQL: Looking forward
- Subscriptions / Async evolutions
- Apollo 3, Hasura
- @defer, @live
- Smarter client-side cache?
- Better mobile clients ecosystem?
- more public APIs?
GraphQL in 2021?
Thank you!
graphql-in-2020
By Charly Poly
graphql-in-2020
- 1,496