Slide 1

Slide 1 text

From learning to thinking in GraphQL @glnnrys Glenn Reyes

Slide 2

Slide 2 text

Glenn Reyes ! @glnnrys Freelance JavaScript Engineer | React & GraphQL

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

What's GraphQL?

Slide 5

Slide 5 text

– graphql.org “GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.” What's GraphQL?

Slide 6

Slide 6 text

{ me { name age bio twitter } } Ask for what you need

Slide 7

Slide 7 text

{ me { name age bio twitter } } { "me" { "name": "Glenn", "age": 31, "bio": "Engineer", "twitter": "@glnnrys" } } Ask for what you need get exactly that

Slide 8

Slide 8 text

/api/v2/ /api/v2/user/143/ me friends REST

Slide 9

Slide 9 text

{ me { name age bio twitter friends { name age } } } GraphQL

Slide 10

Slide 10 text

Core concepts Queries & Mutations Schemas & Types

Slide 11

Slide 11 text

GraphQL server

Slide 12

Slide 12 text

apollo-server const typeDefs = gql` type User { id: ID! name: String } type Query { me: User } `; const resolvers = { Query: { me: (obj, args, context) => getUserById(context.user.id), }, }; const server = new ApolloServer({ typeDefs, resolvers }); server.listen().then(({ url }) => { console.log(` Server ready at ${url}`); });

Slide 13

Slide 13 text

Graphpack

Slide 14

Slide 14 text

⚡ Zero-config GraphQL server ⚡ Run server by single command ⚡ Uses Apollo-Server under the hood ⚡ TypeScript support ⚡ Live-Reload ⚡ ES features ⚡ Friendly Errors ⚡ Hides all the boilerplate Graphpack

Slide 15

Slide 15 text

src !"" resolvers.js #"" schema.graphql

Slide 16

Slide 16 text

CLI $ graphpack # start dev $ graphpack build # create build

Slide 17

Slide 17 text

"scripts": { "start": "graphpack"
 "build": "graphpack build" } package.json

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

Use tools and focus on writing GraphQL

Slide 21

Slide 21 text

github.com/glennreyes/graphpack

Slide 22

Slide 22 text

How to start writing GraphQL?

Slide 23

Slide 23 text

Create Mental Model Define Types Implement Resolvers How to start writing GraphQL?

Slide 24

Slide 24 text

First step Create mental model

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

User Post

Slide 27

Slide 27 text

User Post posts

Slide 28

Slide 28 text

User Post Photo coverPhoto profilePhoto posts

Slide 29

Slide 29 text

Second step Define types

Slide 30

Slide 30 text

# src/schema.graphql type User { coverPhoto: String! profilePhoto: String! displayName: String id: ID! username: ID! bio: String posts: [String!]! }

Slide 31

Slide 31 text

# src/schema.graphql type User { coverPhoto: String! profilePhoto: String! displayName: String id: ID! username: ID! bio: String posts: [String!]! }

Slide 32

Slide 32 text

# src/schema.graphql type User { coverPhoto: String! profilePhoto: String! displayName: String id: ID! username: ID! bio: String posts: [String!]! } posts: [String!]!

Slide 33

Slide 33 text

type Post { id: ID! createdAt: DateTime! message: String! } type User { coverPhoto: String! profilePhoto: String! displayName: String id: ID! username: ID! bio: String posts: [Post!]! } # src/schema.graphql

Slide 34

Slide 34 text

type Post { id: ID! createdAt: DateTime! message: String! } type User { coverPhoto: String! profilePhoto: String! displayName: String id: ID! username: ID! bio: String post: [Post!]! } # src/schema.graphql coverPhoto: String! profilePhoto: String!

Slide 35

Slide 35 text

type Photo { createdAt: String! filename: String! title: String url: String! updatedAt: DateTime! } type Post { id: ID! createdAt: DateTime! message: String! } type User { coverPhoto: Photo! profilePhoto: Photo! displayName: String id: ID! username: ID! bio: String post [Post!]! }

Slide 36

Slide 36 text

Prefer Object Types over Default Types

Slide 37

Slide 37 text

Third step Implement resolvers

Slide 38

Slide 38 text

# src/schema.graphql const resolvers = { Query: { user: (obj, args) => getUser(args.id), }, User: { posts: (obj, args) => getPostsByUser(args.id), }, };

Slide 39

Slide 39 text

How does the query look like?

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

{ "user": { "profilePhotoId": "15942", "coverPhotoId": "159425", "displayName": "Glenn Reyes", "userName": "glnnrys", } } /api/user/glnnrys /api/photo/159425 { "photo": { "id": "159425", "url": "https://myimgcdn.com/159425.jpg", "taggedUsers": ["thekitze", "mmatuzo"] } } /api/user/thekitze { "user": { "profilePhotoId": "15934", "coverPhotoId": "159655", "displayName": "Kitze", "userName": "thekitze", } }

Slide 42

Slide 42 text

query getProfile { profile(username: "glnnrys") { coverPhoto profilePhoto displayName username bio posts { date id message } } }

Slide 43

Slide 43 text

import gql from 'graphql-tag'; import { Query } from 'react-apollo'; const ProfilePage = props => ( {({ data, loading }) => { if (loading) return 'Loading ...'; if (!data) return null; return ; }} );

Slide 44

Slide 44 text

When it gets big and slow ...

Slide 45

Slide 45 text

Fourth step Defer expensive parts

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

Profile Posts

Slide 48

Slide 48 text

query getProfile { profile(username: "glnnrys") { coverPhoto profilePhoto displayName username bio } } query getPosts { profile(username: "glnnrys") { posts { date id message } } }

Slide 49

Slide 49 text

only available in the alpha preview of Apollo! query getProfile { profile(username: "glnnrys") { coverPhoto profilePhoto displayName username bio posts @defer { date id message } } }

Slide 50

Slide 50 text

How about mutations?

Slide 51

Slide 51 text

# src/schema.graphql type Mutation { changeProfilePhoto(input: ChangeProfilePhotoInput!): ChangeProfilePhotoPayload! }

Slide 52

Slide 52 text

# src/schema.graphql type Mutation { changeProfilePhoto( input: ChangeProfilePhotoInput! ): ChangeProfilePhotoPayload! } input ChangeProfilePhotoInput { user: User! file: File! } type ChangeProfilePhotoPayload { clientMutationId: ID! photo: Photo! }

Slide 53

Slide 53 text

⭐ Naming – Verb + Object (eg. updateBio, submitPost) ⭐ Specificity – Make mutations as specific as possible ⭐ Input object – Single, unique & required ⭐ Unique Payload type – Like ChangeProfilePhotoPayload ⭐ Nesting is fine! https://blog.apollographql.com/designing-graphql-mutations-e09de826ed97

Slide 54

Slide 54 text

How about auth?

Slide 55

Slide 55 text

// src/context.js const context = (req) => { const isLoggedIn = req.user ? true : false; return { isLoggedIn, user, }; }; export default context; Context

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Context is also great for access control

Slide 58

Slide 58 text

Batching requests

Slide 59

Slide 59 text

/api/user/1 /api/user/2 /api/user/3

Slide 60

Slide 60 text

/api/user/1 /api/user/2 /api/user/3 === /api/users/?ids=1,2,3

Slide 61

Slide 61 text

Dataloader for batching and caching

Slide 62

Slide 62 text

// src/context.js const context = { users: new DataLoader(keys => fetch(`/api/users/?ids=${keys.join(',')}`)), } // src/resolvers.js const resolvers { Query: { user: (obj, args, context) => context.users.load(args.id), }, };

Slide 63

Slide 63 text

Allows to avoid overfetching

Slide 64

Slide 64 text

Storing data

Slide 65

Slide 65 text

Storing data MySQL MongoDB PostgreSQL RethinkDB MariaDB

Slide 66

Slide 66 text

knex.js const knex = require('knex')({ client: 'mysql', version: '8.0', connection: { host : '127.0.0.1', user : 'your_database_user', password : 'your_database_password', database : 'myapp_test' } }); knex .select(['id', 'name', 'bio']) .from('people') .where({ gender: 'female' })

Slide 67

Slide 67 text

prisma.createPerson({ email: "[email protected]", posts: { create: { title: "GraphQL Conf 2019" } } })

Slide 68

Slide 68 text

Folder structure

Slide 69

Slide 69 text

src !"" resolvers.js #"" schema.graphql Simple

Slide 70

Slide 70 text

src !"" models % !"" createSpeaker.js % !"" createTalk.js % !"" deleteSpeaker.js % !"" getSpeakerById.js % !"" getSpeakers.js % !"" getTalkById.js % #"" getTalks.js !"" resolvers % !"" Mutation.js % !"" Query.js % !"" Speaker.js % !"" Talk.js % #"" index.js #"" types !"" Mutation.graphql !"" Query.graphql !"" Speaker.graphql !"" Talk.graphql #"" schema.graphql By types

Slide 71

Slide 71 text

src !"" Mutation % !"" resolver.js % #"" type.graphql !"" Query % !"" helpers.js % !"" models.js % !"" resolver.js % #"" type.graphql !"" Speaker % !"" resolver.js % #"" type.graphql #"" Talk !"" resolver.js #"" type.graphql By feature

Slide 72

Slide 72 text

Always start simple Switch gruadually depending on your use case Dont worry much about folder structure!!

Slide 73

Slide 73 text

⚡ GraphQL core concepts ⚡ Graphpack – Building zero-config GraphQL servers ⚡ Approach to write – Mental Model, Types, Resolvers, Defer ⚡ Mutations – Naming, Specifity, Unique Input & Payload type ⚡ Authentication & access control ⚡ Data storage – GraphQL not tied to any database ⚡ Batch and cache with Dataloader ⚡ Avoid bikeshedding on folder structure

Slide 74

Slide 74 text

Thank You! @glnnrys Glenn Reyes