PLEASE DOWNLOAD REPO AND INSTALL MODULES
github.com/Danilo-Zekovic/oscon-graphql-starter.git
Or just search github oscon-graphql-starter
Fundamentals of graphQL
A presentation at OSCON2018
Tech Prep
- Please attach to the link
- slides.com/capouch/oscon18/live
- Live URLs and cut-and-paste
- Milestone branches
- Type it in versus cut and paste
Network Time
Quick survey time
Who's out there??
- Already using graphQL?
- Maintain REST endpoint code?
- Coding in JavaScript?
- If so, exclusively ES6+?
- SQL literate?
- Old hand git clone; npm install; npm start?
Please do the evaluation
The Plan
- Overview
- Types and schemas
- The graphiQL tool
- Queries, mutations, subscriptions
- Resolvers
- Tools and interfaces
- Example application w/Gatsby
Overview
What is graphQL?
Analog of REST
- Facebook, ca. 2012, open sourced 2015
- Addresses known problems with REST
- More sophisticated capabilities
- Widespread adoption
- It is an API specification, not a database system
Why the excitement?
Addresses shortcomings
- Data discovery poor with REST
- Multiple data fetches common
- Fetching extraneous data
- Query validation can be done on client
- Deprecation, additions, changes
More robust
- Typed
- Schema-based
- Advanced syntactic features
- Supports realtime functionality
How do you do it?
That's what we're here for!
The "big four" to mastery
- graphQL-native schema language, SDL
- graphql-js JavaScript wrapper
- Queries
- Resolvers
type Author {
id: ID!
firstName: String
middleInitial: String
lastName: String
posts: [Post]
}
graphQL SDL
const AuthorType = new GraphQLObjectType({
name: 'Author',
description: 'A single post by a single author',
fields: {
id: { type: new GraphQLNonNull(GraphQLID),
resolve: (root, args, context, info) => {
return root.id
}
},
firstName: { type: new GraphQLNonNull(GraphQLString),
resolve: (root, args, context, info) => {
return root.firstName
}
},
middleInitial: { type: new GraphQLNonNull(GraphQLString),
resolve: (root, args, context, info) => {
return root.middleInitial
}
},
partial graphql-js JavaScript wrapper
{
authors {
firstName
middleInitial
lastName
}
}
A simple query
const resolvers = {
Query: {
posts: () => posts,
authors: () => authors,
author: (_, args) => find(authors, { id: args.id }),
post: (_, args) => find(posts, { id: args.id })
},
Resolver functions
Let's get started
Think database
(But graphQL is not a database system!!
Basic Organization
- Schema
- Data type definitions
- Queries
- Mutations
- Subscriptions
- Resolvers
A schema is a set of type definitions
Both the client and server use the schema
An endpoint provides resolvers for a schema
- Usually associated with a URL
- Clients and servers share the schema
- Database backends can connect to resolvers
Each endpoint serves a single schema*
Basic Schema Types
- scalar
- type (as in object type)
- enum
- interface
- union
- input
Basic Schema Types
- scalar
Five built-in scalar types
- Int
- Float
- String
- Boolean
- ID
Custom scalars are possible*
Types can have modifiers, e.g.
- String (nullable)
- String! (non-nullable)
- [String] (list of nullable Strings)
- [String]! (non-null list of nullable Strings)
- [String!]! (non-null list of non-null Strings)
Basic Schema Types
- scalar
- type (as in object type)
Objects are defined with type*
Our starting schema is simple
- Two objects:
- Authors, who create
- Posts
- As we go, we'll add more
type Author {
id: ID!
firstName: String
middleInitial: String
lastName: String
posts: [Post]
}
type Post {
id: ID!
title: String
author: AuthorId
articleType: String
}
Query
Queries are read-only fetch operations
We will define four:
- authors: Gets a list of all authors
- posts: Gets a list of all posts
- author(id: Int): Get a single author, by ID
- post(id: Int): Get a single post, by ID
type Query {
posts: [Post]
authors: [Author]
author(id: Int!): Author
post(id: Int!): Post
}
Introspection
- We're not going to cover it here*
- It's a built-in interface for meta-information discovery
- Its existence is the reason graphiQL is a powerful tool
Introduction to graphiQL
GraphiQL
- In-browser schema-development IDE
- Powerful debugging tool
- Automated documentation (via introspection)
- Is the standard way of assessing a schema
git checkout intro-one
graphql-js vs. graphql-tools
How do they differ?
- graphql-js is the reference implementation
- It is pure JavaScript
- graphql-tools done by folks at Apollo
- Code directly in graphQL's SDL
- Limits to power and complexity
git checkout intro-two-js
Basic Schema Types
- scalar
- type (as in object type)
- enum
Similar to enums in other languages
enum PostType {
NEWS
SPORTS
OPINION
REVIEW
ANALYSIS
TECHNICAL
}
git checkout intro-two
Basic Schema Types
- scalar
- type (as in object type)
- enum
- interface
Semantically similar to other languages
Syntactically, not quite
interface Person {
id: ID!
firstName: String
middleInitial: String
lastName: String
}
type Author implements Person {
id: ID!
firstName: String
middleInitial: String
lastName: String
# Fields unique to the implemented type
posts: [Post]
# This is a derived field
agent: Agent
}
type Agent implements Person {
id: ID!
firstName: String
middleInitial: String
lastName: String
# Field unique to this implemented type
represents: [Author]
}
Let's add some new queries
type Query {
posts: [Post]
authors: [Author]
agents: [Agent]
people: [Person]
author(id: Int!): Author
agent(id: Int!): Agent
}
Interface types are special!!
(see the People resolver later on)
git checkout intro-three
Basic Schema Types
- scalar
- type (as in object type)
- enum
- interface
- union
Unions versus Interfaces
- In graphQL they are very similar
- Interfaces are better when objects share common fields
- Union types are "true types" independently of the union
type Author {
id: ID!
firstName: String
middleInitial: String
lastName: String
posts: [Post]
agent: Agent
}
type Agent {
id: ID!
firstName: String
middleInitial: String
lastName: String
represents: [Author]
}
union People = Author | Agent
git checkout intro-three-unions
Directives
Directives are meta-commands
- Signaled by '@'
- Complex and powerful
- Conditionals, deprecations, renaming
Basic Schema Types
- scalar
- type (as in object type)
- enum
- interface
- union
- input
Input types are required for mutations
Points to note about mutations
- Synchronous (queries are async)
- Fetches the mutated object
- Requires an input type
input PostInput {
title: String
authorId: Int
articleType: PostType
}
We'll need to define the mutation
type Mutation {
createPost(input: PostInput): Post
}
git checkout final
Subscriptions
Still officially "experimental"
- Implement the pub-sub model
- Allow for realtime client data discovery
- Not implemented yet in vanilla graphiQL
# The subscription type
# Specifies possible pub-sub events
type Subscription {
postAdded: Post
}
Subscriptions allow realtime
- Clients can ask for different fields
- pub-sub is arguably similar to the Observer model
- Vanilla graphiQL does not support it yet
Resolvers
What's a graphQL resolver?
- The implementation of a given field in the schema
- Each query requests a series of fields
- Each field's value is provided by its resolver
- Resolvers are opaque to the client
Resolvers can be part of the schema object
(as we saw with graphql-js)
Resolvers get four parameters
- root
- args
- context
- info
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
user: {
type: UserType,
args: {
id: { type: GraphQLID }
},
resolve: (root, args, context, info) => {
const { id } = args
return fetchUserById(id)
}
}
}
})
})
Let's look at our resolvers
const resolvers = {
Query: {
posts: () => posts,
authors: () => authors,
author: (_, args) => find(authors, { id: args.id }),
},
Author: {
posts: (author) => filter(posts, { authorId: author.id }),
},
Post: {
author: (post) => find(authors, { id: post.authorId }),
},
};
intro-one
Tools and Interfaces
"jsFiddle for graphQL"
Launchpad Touts
- Runs in the browser
- Share "pads" with others who can fork them
- Produces downloadable code
- The original code for the tutorial was done this way
- Provides an endpoint for testing
- e.g. with the Chrome graphiQL extension
Some graphQL projects
Sample Gatsby app
About Gatsby
- "Static PWA generator"
- React-based
- graphQL for the data layer
- Deploys from github push
- Based on the JAMstack model
My Gatsby Project
- Built using a Gatsby starter
- In alpha production at sunnycrestfarm.org
- Some comments on its being a PWA
- Multiple branches auto-deploy from github
OSCON18
By capouch
OSCON18
Fundamentals of graphQL
- 2,230