GraphQL
overview
WHo am I
- 周杰 Jay Chou
- 約莫兩年 Web Developer 的 經驗
- 目前在 Yoctol.AI 打工
- Introduction(How to use, how to design API)
- Props and Cons
- Ecosystem(Apollo, GraphQL CDN)
Typescript issue
Intro
- In 2012, From Facebook
- Query Language for API
Intro
How to use
Query
{
"data": {
"human": {
"id": 1000,
"name": "Luke Skywalker",
"height": 172
}
}
}
Response
query {
findHuman {
human(id: "1000") {
id
name
height
}
}
}
Request
(GET )
Mutation
Request
mutation CreateHuman($name: String!, $height: Int!) {
createHuman(name: $name, height: $height) {
id
name
height
}
}
Variables
{
"name": "Jay Chou",
"height": 174,
}
(UPDATE)
Mutation
Request
mutation CreateHuman($name: String!, $height: Int!) {
createHuman(name: $name, height: $height) {
id
name
height
}
}
Variables
{
"name": "Jay Chou",
"height": 174,
}
{
"data": {
"human": {
"id": 1001,
"name": "Jay Chou",
"height": 174
}
}
}
Response
(UPDATE)
Mutation
Request
mutation CreateHuman($name: String!, $height: Int!) {
createHuman(name: $name, height: $height) {
id
name
height
}
}
Variables
{
"name": "Jay Chou",
"height": 174,
}
{
"data": {
"human": {
"id": 1001,
"name": "Jay Chou",
"height": 174
}
}
}
Response
(UPDATE)
Subscription/Fragment/Directive......etc
GraphQL Doc
under the hood
src: https://chanakaudaya.medium.com/graphql-based-solution-architecture-patterns-8905de6ff87e
query {
findHuman {
human(id: "1000") {
id
name
height
}
}
}
gql
under the hood
src: https://chanakaudaya.medium.com/graphql-based-solution-architecture-patterns-8905de6ff87e
query {
findHuman {
human(id: "1000") {
id
name
height
}
}
}
gql
under the hood
gql
1. write gql with the corresponding library
under the hood
gql
/graphql
2. send request via a single URL/endpoint
under the hood
gql
3. resolve gql, get/update data with the corresponding library
under the hood
Post method with JSON Payload
HOW TO Design SCHEMA/API
define Object/write Resolvers
HOW TO Design SCHEMA/API
type Human {
id: ID!
name: String!
height: Int!
clubs: [Club]
}
type Club {
id: ID!
name: String!
}
Object Type
Int
Float
String
Boolean
ID
(Default) Scalar Types
(Custom) Scalar Types
scalar Date
just like define ORM entity to some degree 🤔
HOW TO Design SCHEMA/API
Query: {
human(obj, args, context, info) {
return context.db.loadHumanByID(args.id).then(
userData => new Human(userData)
)
}
}
This example is written in JavaScript, however GraphQL servers can be built in many different languages.
Resolver
Architecture
src: https://chanakaudaya.medium.com/graphql-based-solution-architecture-patterns-8905de6ff87e
Architecture
src: https://chanakaudaya.medium.com/graphql-based-solution-architecture-patterns-8905de6ff87e
Architecture
Props & Cons
Props in my opinion
- Auto Documentation(Introspection)
- Better DX
- Reduce Bandwidth
- Strictly-typed interfaces
Auto Documentation
(Introspection)
{
"data": {
"__schema": {
"types": [
{
"name": "Query"
},
{
"name": "String"
},
{
"name": "ID"
},
{
"name": "Mutation"
},
{
"name": "Episode"
},
{
"name": "Character"
},
{
"name": "Int"
},
{
"name": "LengthUnit"
},
{
"name": "Human"
},
{
"name": "Float"
},
{
"name": "Droid"
},
{
"name": "FriendsConnection"
},
{
"name": "FriendsEdge"
},
{
"name": "PageInfo"
},
{
"name": "Boolean"
},
{
"name": "Review"
},
{
"name": "ReviewInput"
},
{
"name": "Starship"
},
{
"name": "SearchResult"
},
{
"name": "__Schema"
},
{
"name": "__Type"
},
{
"name": "__TypeKind"
},
{
"name": "__Field"
},
{
"name": "__InputValue"
},
{
"name": "__EnumValue"
},
{
"name": "__Directive"
},
{
"name": "__DirectiveLocation"
}
]
}
}
}
Response
query {
__schema {
types {
name
}
}
}
Request
BETTER dx
.gql easy to understand
query {
findHuman {
human(id: "1000") {
id
name
height
clubs {
id
name
}
}
}
}
nested data
BETTER dx
query {
findHuman {
human(id: "1000") {
id
name
height
clubs {
id
name
}
}
}
}
nested data
Less time spent documenting and navigating APIs
REDUCE BANDWIDTH
Let's talk about REST first
REDUCE BANDWIDTH
- Over-fetching
- Multiple requests for multiple resources
- Waterfall network requests on nested data
- Each client need to know the location of each service
In REST comes with some downsides like:
REDUCE BANDWIDTH
- Over-fetching
- Multiple requests for multiple resources
- Waterfall network requests on nested data
- Each client need to know the location of each service
In REST comes with some downsides like:
query {
findHuman {
human(id: "1000") {
id
name
height
clubs {
id
name
}
}
project (id: '123') {
id
name
}
}
}
REST
https://www.howtographql.com/basics/1-graphql-is-the-better-rest
multi request
GraphQL
https://www.howtographql.com/basics/1-graphql-is-the-better-rest
single request
SINGLE ENDPOINT
No more Over- and Under-fetching
Over-fetching: Downloading superfluous data
Under-fetching and the n+1 problem
https://www.howtographql.com/basics/1-graphql-is-the-better-rest
Concern: Request JSON payload cost more bytes?
This is a trade off, but here come some solution ......
We will explain later🤪
CONS in my opinion
- Make your architecture more complicated
- Http cache
Make your architecture more complicated
more code/more library to learn/more bundle size/securitiy issue
If front-end dev not familiar with graphQL schema,
he/she will get useless field and cost performance
-> trigger fieldResolver
Make your architecture more complicated
more code/more library to learn/more bundle size/securitiy issue
Make your architecture more complicated
more code/more library to learn/more bundle size/securitiy issue
Introspection/Authorize issue
Http cache
By providing many endpoints, a REST API enables easy web caching configurations to match certain URL patterns, HTTP methods, or specific resources.
Due to having only one endpoint with many different queries, it’s much harder to use this type of caching with a GraphQL API.
Lets talk more about cache
Apollo Tech-talk: Simple caching, made difficult
Responses to [the POST] method are not cacheable, unless the response includes appropriate Cache-Control or Expires header fields
Change POST TO GET
You can't use GET since query parameters have size limits!
URI length issue
狠角色
Solution
Application/Network
Application
- Check URI length
- Persisted Queries
- Apollo server/Apollo client
CHECK URI LENGTH
export default function request(url, query, variables) {
return fetch(`${url}?query=${query}&variables=${variables}`)
.then(result => {
if (result.status !== 414) {
return result;
}
return fetch(url, {
method: 'POST',
body: JSON.stingify({ query, variables })
});
})
}
Persisted Queries
- use Get method to help CDN cache
- hash payload, let cache easier
- reduce the time of server resolve graphQL query
Apollo Persist Queries
Apollo client
Apollo Client stores the results of your GraphQL queries in a local, normalized, in-memory cache.
This enables Apollo Client to respond almost immediately to queries for already-cached data, without even sending a network request.
manage API state
Apollo client Cache
Globally Unique ID: _typename + id
{
"__typename": "Person",
"id": "cGVvcGxlOjE=",
"name": "Luke Skywalker",
"homeworld": {
"__typename": "Planet",
"id": "cGxhbmV0czox",
"name": "Tatooine"
}
}
{
"__typename": "Person",
"id": "cGVvcGxlOjE=",
"name": "Luke Skywalker",
"homeworld": {
"__ref": "Planet:cGxhbmV0czox"
}
}
Apollo client Cache
{
"__typename": "Person",
"id": "cGVvcGxlOjE=",
"name": "Luke Skywalker",
"homeworld": {
"__typename": "Planet",
"id": "cGxhbmV0czox",
"name": "Tatooine"
}
}
{
"__typename": "Person",
"id": "cGVvcGxlOjE=",
"name": "Luke Skywalker",
"homeworld": {
"__ref": "Planet:cGxhbmV0czox"
}
}
Globally Unique ID: _typename + id
Apollo Server Cache
type Post {
id: ID!
title: String
author: Author
votes: Int @cacheControl(maxAge: 30)
comments: [Comment]
readByCurrentUser: Boolean! @cacheControl(maxAge: 10, scope: PRIVATE)
}
schema
Apollo Server Cache
Whenever Apollo Server sends an operation response that has a non-zero maxAge, it includes a Cache-Control HTTP header that describes the response's cache policy.
Cache-Control: max-age=60, private
HTTP header format
But there are problems with these though.
Similar queries
query {
food {
title
}
}
query {
food {
title
body
}
}
query {
# with comments
food {
title
}
}
generate different cache keys -> In reality
not smart enough 😢
NETWORK
Another cache issue solution: GraphQL CDN
Graphql CDN
creator of Styled Component
- Advanced Edge Network
- Per-user Caching
- API Analytics & Insights
- Malicious Query Detection
More Info -> https://graphcdn.io
REFERENCE
- GraphQL Doc
- Apollo GraphQL Doc
- https://hackmd.io/C2yzLJJETLq3lNYM_cHzGw
- https://hackmd.io/NG2Rm8IVSHy30nLSo_OG0A
One More thing
Valley22
投資了酒吧,在信義安和捷運站旁邊,歡迎大家蒞臨😎
GraphQL-Overview
By Jay Chou
GraphQL-Overview
- 439