Slide 1

Slide 1 text

Beyond REST API @Linminphyoe1 https://lin.phyo.work better.hr

Slide 2

Slide 2 text

We all know REST API

Slide 3

Slide 3 text

What we faced @ Better HR

Slide 4

Slide 4 text

V1

Slide 5

Slide 5 text

API Schema • V1 • GET https://www.better.hr/api/web/profile/{id} • GET https://www.better.hr/api/web/profiles

Slide 6

Slide 6 text

V2

Slide 7

Slide 7 text

V2 Changes • New tab for Activity Log is added • Create new API for Activity Log

Slide 8

Slide 8 text

API Schema • V2 • GET https://www.better.hr/api/web/profile/{id} • GET https://www.better.hr/api/web/profiles • GET https://www.better.hr/api/web/activiylog/{id} • GET https://www.better.hr/api/web/activiylogs

Slide 9

Slide 9 text

V3

Slide 10

Slide 10 text

V3 Changes • Added Payroll tab • Move payroll related fields from profile to payroll tab • Clean up old API

Slide 11

Slide 11 text

API Schema • V3 • GET https://www.better.hr/api/web/profile/{id} • GET https://www.better.hr/api/web/profiles • GET https://www.better.hr/api/web/activiylog/{id} • GET https://www.better.hr/api/web/activiylogs • GET https://www.better.hr/api/web/payroll/{id} • GET https://www.better.hr/api/web/payrolls

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

And .. Mobile Apps

Slide 14

Slide 14 text

Things to consider for Mobile Apps • JSON should be as lightweight as possible • Backward compatible APIs

Slide 15

Slide 15 text

Mobile endpoints • GET https://www.better.hr/api/mobile/profile/{id} • GET https://www.better.hr/api/mobile/profiles • GET https://www.better.hr/api/mobile/activiylog/{id} • GET https://www.better.hr/api/mobile/activiylogs • GET https://www.better.hr/api/mobile/payroll/{id} • GET https://www.better.hr/api/mobile/payrolls

Slide 16

Slide 16 text

12 APIs now. It is GET method only now

Slide 17

Slide 17 text

2 Web Devs 1 Frontend, 1 Backend, New releases every week

Slide 18

Slide 18 text

Backend Dev

Slide 19

Slide 19 text

Future We foresee other problems, too.

Slide 20

Slide 20 text

Maintaining It’s not that easy

Slide 21

Slide 21 text

Maintaining • API schema is growing fast • Single Source of Truth doesn’t exist

Slide 22

Slide 22 text

Versioning Another problem after going production

Slide 23

Slide 23 text

Versioning • https://www.better.hr/api/web/v1/….. • https://www.better.hr/api/web/v2/….. • https://www.better.hr/api/mobile/v1/….. • https://www.better.hr/api/mobile/v2/….. API endpoints doubled

Slide 24

Slide 24 text

Upcoming features …

Slide 25

Slide 25 text

Fingerprints Employee Schedules Contacts Notifications Attendances Leaves Team’s attendance Team’s leaves Login Files Assets Policies Permissions Profile

Slide 26

Slide 26 text

What we realize • More frequent changes = More problems • More releases = More problems • More feature changes = More problems • More UI changes = More problems

Slide 27

Slide 27 text

Explore a new thing. • Reduce loads of API developers • Want Single Source of Truth • Lightweight network calls • Easy to evolve over time • Want to experiment something new

Slide 28

Slide 28 text

We found GraphQL

Slide 29

Slide 29 text

How is it differ from REST ?

Slide 30

Slide 30 text

GraphQL is Inversion of Control

Slide 31

Slide 31 text

Backend Dev Frontend Dev Mobile Dev - Build API - Make changes Consumes API Consumes API REST

Slide 32

Slide 32 text

Backend Dev Frontend Dev Mobile Dev Build Schema, which information is opened for clients Consumes API Consumes API GraphQL Ask required information Ask required information

Slide 33

Slide 33 text

Ref : https://blog.apollographql.com/graphql-vs-rest-5d425123e34b

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

GraphQL opens querying fields from Front-end developer, not defined by API developer.

Slide 37

Slide 37 text

Magic?

Slide 38

Slide 38 text

NO

Slide 39

Slide 39 text

GraphQL is an extension built on top of REST API

Slide 40

Slide 40 text

REST curl -X GET -H "Content-Type: application/json" https://www.example.com/users

Slide 41

Slide 41 text

REST curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ users { name } }" }' https://www.example.com/graphql curl -X GET -H "Content-Type: application/json" https://www.example.com/users GraphQL

Slide 42

Slide 42 text

curl -X GET -H "Content-Type: application/json" https://www.example.com/users curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ users { name } }" }' https://www.example.com/graphql REST GraphQL

Slide 43

Slide 43 text

So, how do I know which information client can get?

Slide 44

Slide 44 text

Server Side I can give you this User info : ID, Name, Nick Name, Job Title, Salary, Phone, Address, Gender

Slide 45

Slide 45 text

type User { id : String name: String nickName: String jobTitle : String salary : Float phone : String address : String gender : Gender } I can give you this User info : ID, Name, Nick Name, Job Title, Salary, Phone, Address, Gender GraphQL Schema

Slide 46

Slide 46 text

What is GraphQL Schema

Slide 47

Slide 47 text

GraphQL Schema • Provided by Backend • Documentation that shows information provided for clients https://graphql.org/learn/schema/

Slide 48

Slide 48 text

type User { id : String name: String nickName: String jobTitle : String salary : Float phone : String address : String gender : Gender } I can give you this User info : ID, Name, Nick Name, Job Title, Salary, Phone, Address, Gender GraphQL Schema

Slide 49

Slide 49 text

Okay. Give me Name & Phone Client Side Client wants some information

Slide 50

Slide 50 text

Query query { user { name phone } } Okay. Give me Name & Phone

Slide 51

Slide 51 text

Result { "data": { “user": { "name": "Lin Phyo", "phone": “+959950001234" } } } query { user { name phone } } API returns

Slide 52

Slide 52 text

Result { "data": { “user": { "name": "Lin Phyo", "phone": “+959950001234”, "email": “[email protected]”, } } } query { user { name phone email } } API returns Request Parameter

Slide 53

Slide 53 text

Result { "data": { “user": { "id": “u0001”, "name": "Lin Phyo", "phone": “+959950001234”, "email": “[email protected]”, } } } query { user { id name phone email } } API returns Request Parameter

Slide 54

Slide 54 text

GraphQL - A query language

Slide 55

Slide 55 text

select * from user

Slide 56

Slide 56 text

select * from user select name, phone from user

Slide 57

Slide 57 text

query { users { name phone } } select name, phone from user

Slide 58

Slide 58 text

query { users { name phone } } select name, phone from user

Slide 59

Slide 59 text

query { users { name phone } } select name, phone from user

Slide 60

Slide 60 text

query { users { name phone } } select name, phone from user

Slide 61

Slide 61 text

query { users { name phone } } select name, phone from user where id = 1

Slide 62

Slide 62 text

query { users( id = 1 ) { name phone } } select name, phone from user where id = 1

Slide 63

Slide 63 text

query { users( id = 1 ) { name phone } } select name, phone from user where id = 1

Slide 64

Slide 64 text

Mutation Equivalent to POST in REST

Slide 65

Slide 65 text

You can update this User information : Nick Name, Phone & Address Server Side Client wants to update some information

Slide 66

Slide 66 text

Okay. I want to update Nick name & Phone Client Side Client wants to update some information

Slide 67

Slide 67 text

Mutation mutation { }

Slide 68

Slide 68 text

Mutation mutation { updateMe(nickName:”Lin Phyo”, phone:”0987654321” ) { ... } }

Slide 69

Slide 69 text

Mutation mutation { updateMe(nickName:”Lin Phyo”, phone:”0987654321” ) { updatedAt } }

Slide 70

Slide 70 text

Mutation mutation { updateMe(nickName:”Lin Phyo”, phone:”0987654321” ) { updatedAt nickName Phone } }

Slide 71

Slide 71 text

GraphQL Workflow

Slide 72

Slide 72 text

https://lighthouse-php.com/tutorial/#what-is-lighthouse

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

No content

Slide 79

Slide 79 text

GraphQL Server GraphQL Client

Slide 80

Slide 80 text

React import gql from 'graphql-tag'; import { useQuery } from '@apollo/react-hooks'; const GET_DOGS = gql` { dogs { id breed } } `; const { loading, error, data } = useQuery(GET_DOGS);

Slide 81

Slide 81 text

React import gql from 'graphql-tag'; import { useQuery } from '@apollo/react-hooks'; const GET_DOGS = gql` { dogs { id breed } } `; const { loading, error, data } = useQuery(GET_DOGS);

Slide 82

Slide 82 text

Android / iOS > apollo client:download-schema [OUTPUT] Download GraphQL Schema provided by backend

Slide 83

Slide 83 text

Android / iOS > apollo client:download-schema [OUTPUT] Put it inside project

Slide 84

Slide 84 text

Android / iOS > apollo client:download-schema [OUTPUT] Put it inside project query GetMyProfile { me{ id name email } } Write the query you want : GetMyProfile.graphql

Slide 85

Slide 85 text

Android / iOS > apollo client:download-schema [OUTPUT] Put it inside project Write the query you want : GetMyProfile.graphql Build Project which will automatically run > apollo client:codegen [OUTPUT] API.swift for iOS or GetMyProfileQuery.java

Slide 86

Slide 86 text

Android / iOS > apollo client:download-schema [OUTPUT] Put it inside project Write the query you want : GetMyProfile.graphql Build Project which will automatically run > apollo client:codegen [OUTPUT] Use generated method or class to call API

Slide 87

Slide 87 text

More about GraphQL

Slide 88

Slide 88 text

Named Queries

Slide 89

Slide 89 text

Without Naming query { users( id = 1 ) { name phone } }

Slide 90

Slide 90 text

Named Query query GetUser { users( id = 1 ) { name phone } }

Slide 91

Slide 91 text

Variables

Slide 92

Slide 92 text

Without Variables query GetUser { users( id = 1 ) { name phone } }

Slide 93

Slide 93 text

With Variables query GetUser($id : Int) { users( id = $id ) { name phone } } { “id” : 1 }

Slide 94

Slide 94 text

Aliasing Mapping fields as required

Slide 95

Slide 95 text

Without Aliasing query GetUser($id : Int) { users( id = $id ) { name phone } } { “id” : 1 }

Slide 96

Slide 96 text

With Aliasing query GetUser($id : Int) { employees : users( id = $id ) { name phone } } { “id” : 1 }

Slide 97

Slide 97 text

Enums

Slide 98

Slide 98 text

Enums enum EmployeeStatus { ACTIVE, DEACTIVE, DELETE }

Slide 99

Slide 99 text

Enums enum EmployeeStatus { ACTIVE, DEACTIVE, DELETE } type User { name : String, status : EmployeeStatus }

Slide 100

Slide 100 text

Enums query GetEmployeeStatuses { users { name status } } type User { name : String, status : EmployeeStatus }

Slide 101

Slide 101 text

Enums query GetEmployeeStatuses { users { name status } } { "data": { "users": [ { "name": “John Doe", "status": "ACTIVE" }, ... ] } }

Slide 102

Slide 102 text

Enums { "data": { "users": [ { "name": “John Doe", "status": "ACTIVE" }, ... ] } } enum EmployeeStatus { ACTIVE, DEACTIVE, DELETE }

Slide 103

Slide 103 text

Interfaces

Slide 104

Slide 104 text

Interfaces interface Notification{ id: ID! title: String! description: String! }

Slide 105

Slide 105 text

Interfaces type NotiTypeA implements Notification { id: ID! title: String! description: String! } interface Notification{ id: ID! title: String! description: String! }

Slide 106

Slide 106 text

Interfaces interface Notification{ id: ID! title: String! description: String! } type NotiTypeB implements Notification { id: ID! title: String! description: String! attachmentsUrls: [String!]! } type NotiTypeA implements Notification { id: ID! title: String! description: String! }

Slide 107

Slide 107 text

Unions

Slide 108

Slide 108 text

Unions union User = DashboardUser | MobileUser | NonMobileUser

Slide 109

Slide 109 text

Unions union User = DashboardUser | MobileUser | NonMobileUser { users { ... on DashboardUser { role } ... on MobileUser { deviceID } ... on NonMobileUser { officeID } } }

Slide 110

Slide 110 text

Unions union User = DashboardUser | MobileUser | NonMobileUser { users { ... on DashboardUser { role } ... on MobileUser { deviceID } ... on NonMobileUser { officeID } } }

Slide 111

Slide 111 text

Unions union User = DashboardUser | MobileUser | NonMobileUser { users { ... on DashboardUser { role } ... on MobileUser { deviceID } ... on NonMobileUser { officeID } } }

Slide 112

Slide 112 text

Unions union User = DashboardUser | MobileUser | NonMobileUser { users { ... on DashboardUser { role } ... on MobileUser { deviceID } ... on NonMobileUser { officeID } } }

Slide 113

Slide 113 text

Fragments Grouping same structure for code reuse

Slide 114

Slide 114 text

Fragments fragment NameAndProfile on User{ name: String! profileUrl: String! }

Slide 115

Slide 115 text

Fragments fragment NameAndProfile on User{ name: String! profileUrl: String! } query { users { ... NameAndProfile } }

Slide 116

Slide 116 text

Subscriptions Real-time GraphQL queries

Slide 117

Slide 117 text

Error Handling

Slide 118

Slide 118 text

Error format { "data": { ... }, "errors": [ ... ] }

Slide 119

Slide 119 text

Resources GraphQL Official Website https://graphql.org/ Explore GraphQL https://graphql.com/

Slide 120

Slide 120 text

Tooling Altair GraphQL Client https://altair.sirmuel.design/ IntelliJ Plugin https://github.com/jimkyndemeyer/js-graphql-intellij-plugin Apollo Platform https://www.apollographql.com/docs/intro/platform Apollo CLI https://github.com/apollographql/apollo-tooling

Slide 121

Slide 121 text

Apollo Platform • Apollo Server • Apollo Client • iOS and Android • Apollo CLI https://www.apollographql.com/docs/intro/platform#open- source

Slide 122

Slide 122 text

Final Thoughts

Slide 123

Slide 123 text

Is that perfect?

Slide 124

Slide 124 text

No

Slide 125

Slide 125 text

Drawbacks • Multipart request is not out of the box • Server side caching is harder compared to REST • Rate limiting for public APIs • Careless developers problem • Project handover

Slide 126

Slide 126 text

But, we gain • Write once, query anywhere • Single source of truth • Faster frontend, mobile development • Able to call different data nodes in one API call • Easier to analyze which fields are requested by whom • Easier to grow overtime • Performant API

Slide 127

Slide 127 text

Drawbacks faced by Mobile Developers • Generated model is not ready to use • Tons of null checks

Slide 128

Slide 128 text

Which companies are using GraphQL ??

Slide 129

Slide 129 text

… better.hr

Slide 130

Slide 130 text

Should I use GraphQL in our project ??

Slide 131

Slide 131 text

It depends.

Slide 132

Slide 132 text

• Long term project • Products • Different clients using the same backend • Open-source APIs

Slide 133

Slide 133 text

Playground https://api.spacex.land/graphql

Slide 134

Slide 134 text

Write queries, not codes @Linminphyoe1 https://lin.phyo.work https://speakerdeck.com/hashlin Get the slides @

Slide 135

Slide 135 text

@Linminphyoe1 https://lin.phyo.work Take a ride through a Burmese tech scene made by Burmese, for Burmese https://anchor.fm/techshaw @vincentpaing