GraphQL, REST or RPC? Making the choice!

A presentation at PHP UK in February 2023 in London, UK by Rob Allen

Slide 1

Slide 1

GraphQL, REST or RPC? Making the choice! Rob Allen PHPUK, February 2023

Slide 2

Slide 2

Fit for Purpose Rob Allen @akrabat @rob@akrabat.com

Slide 3

Slide 3

API Architecture Rob Allen @akrabat @rob@akrabat.com

Slide 4

Slide 4

APIs can be realised in any style but, which makes the most sense? Rob Allen @akrabat @rob@akrabat.com

Slide 5

Slide 5

RPC APIs Rob Allen @akrabat @rob@akrabat.com

Slide 6

Slide 6

RPC APIs • Call a function on a remote server Rob Allen @akrabat @rob@akrabat.com

Slide 7

Slide 7

RPC APIs • Call a function on a remote server • Common implementations: JSON-RPC, SOAP, gRPC Rob Allen @akrabat @rob@akrabat.com

Slide 8

Slide 8

RPC APIs • Call a function on a remote server • Common implementations: JSON-RPC, SOAP, gRPC • Tends to require a schema (WSDL, ProtoBuf Defintion) Rob Allen @akrabat @rob@akrabat.com

Slide 9

Slide 9

Ethereum JSON-RPC Request: POST / HTTP/1.1 Host: localhost:8545 { “jsonrpc”:”2.0”, “id”:1, “method”:”net_peerCount”, “params”:[] } Rob Allen @akrabat @rob@akrabat.com

Slide 10

Slide 10

Ethereum JSON-RPC Response: { “id”:1, “jsonrpc”: “2.0”, “result”: “0x2” } Rob Allen @akrabat @rob@akrabat.com

Slide 11

Slide 11

gRPC Interact via PHP library: $client = new RouteGuideClient(‘localhost:50051’); $p = new Routeguide\Point(); $p->setLatitude(409146138); $p->setLongitude(-746188906); list($feature, $status) = $client->GetFeature($p)->wait(); Rob Allen @akrabat @rob@akrabat.com

Slide 12

Slide 12

RESTful APIs Rob Allen @akrabat @rob@akrabat.com

Slide 13

Slide 13

RESTful APIs • Operate on a representation of the state of a resource though HTTP verbs Rob Allen @akrabat @rob@akrabat.com

Slide 14

Slide 14

RESTful APIs • Operate on a representation of the state of a resource though HTTP verbs • HTTP native Rob Allen @akrabat @rob@akrabat.com

Slide 15

Slide 15

RESTful APIs • Operate on a representation of the state of a resource though HTTP verbs • HTTP native • Uniform interface Rob Allen @akrabat @rob@akrabat.com

Slide 16

Slide 16

RESTful APIs • Operate on a representation of the state of a resource though HTTP verbs • HTTP native • Uniform interface • Hypermedia controls Rob Allen @akrabat @rob@akrabat.com

Slide 17

Slide 17

RESTful APIs PUT /users/ba60c99fd3 Content-Type: application/json Accept: application/json { “name”: “Rob Allen” “email”: “rob@akrabat.com” } Rob Allen @akrabat @rob@akrabat.com

Slide 18

Slide 18

RESTful APIs PUT /users/ba60c99fd3 Content-Type: application/json Accept: application/json { “name”: “Rob Allen” “email”: “rob@akrabat.com” } Rob Allen @akrabat @rob@akrabat.com

Slide 19

Slide 19

RESTful APIs PUT /users/ba60c99fd3 Content-Type: application/json Accept: application/json { “name”: “Rob Allen” “email”: “rob@akrabat.com” } Rob Allen @akrabat @rob@akrabat.com

Slide 20

Slide 20

RESTful APIs PUT /users/ba60c99fd3 Content-Type: application/json Accept: application/json { “name”: “Rob Allen” “email”: “rob@akrabat.com” } Rob Allen @akrabat @rob@akrabat.com

Slide 21

Slide 21

RESTful APIs: Response HTTP/1.1 201 Created Content-Type: application/hal+json ETag: dfb9f2ab35fe4d17bde2fb2b1cee88c1 { “name”: “Rob Allen” “email”: “rob@akrabat.com”, “_links”: { “self”: “https://api.example.com/user/ba60c99fd3” } } Rob Allen @akrabat @rob@akrabat.com

Slide 22

Slide 22

RESTful APIs HTTP/1.1 201 Created Content-Type: application/hal+json ETag: dfb9f2ab35fe4d17bde2fb2b1cee88c1 { “name”: “Rob Allen” “email”: “rob@akrabat.com”, “_links”: { “self”: “https://api.example.com/user/ba60c99fd3” } } Rob Allen @akrabat @rob@akrabat.com

Slide 23

Slide 23

RESTful APIs HTTP/1.1 201 Created Content-Type: application/hal+json ETag: dfb9f2ab35fe4d17bde2fb2b1cee88c1 { “name”: “Rob Allen” “email”: “rob@akrabat.com”, “_links”: { “self”: “https://api.example.com/user/ba60c99fd3” } } Rob Allen @akrabat @rob@akrabat.com

Slide 24

Slide 24

RESTful APIs HTTP/1.1 201 Created Content-Type: application/hal+json ETag: dfb9f2ab35fe4d17bde2fb2b1cee88c1 { “name”: “Rob Allen” “email”: “rob@akrabat.com”, “_links”: { “self”: “https://api.example.com/user/ba60c99fd3” } } Rob Allen @akrabat @rob@akrabat.com

Slide 25

Slide 25

GraphQL APIs Rob Allen @akrabat @rob@akrabat.com

Slide 26

Slide 26

GraphQL APIs • Retrieve only the data you need on consumer side Rob Allen @akrabat @rob@akrabat.com

Slide 27

Slide 27

GraphQL APIs • Retrieve only the data you need on consumer side • Reduce the number of calls to retrieve data with embedded resources Rob Allen @akrabat @rob@akrabat.com

Slide 28

Slide 28

GraphQL APIs • Retrieve only the data you need on consumer side • Reduce the number of calls to retrieve data with embedded resources • Self-describing schema Rob Allen @akrabat @rob@akrabat.com

Slide 29

Slide 29

Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen @akrabat @rob@akrabat.com

Slide 30

Slide 30

Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen @akrabat @rob@akrabat.com

Slide 31

Slide 31

Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen @akrabat @rob@akrabat.com

Slide 32

Slide 32

Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen @akrabat @rob@akrabat.com

Slide 33

Slide 33

Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen @akrabat @rob@akrabat.com

Slide 34

Slide 34

Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen @akrabat @rob@akrabat.com

Slide 35

Slide 35

Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen @akrabat @rob@akrabat.com

Slide 36

Slide 36

Queries: Result “data”: { “author”: { “id”: “MXxBdXRob3J8ZjA”, “name”: “Anne McCaffrey”, “books”: { “totalCount”: 6, “edges”: [ { “node”: { “id”: “MXxCb29rfGYwNzU”, “title”: “Dragonflight” } }, Rob Allen @akrabat @rob@akrabat.com

Slide 37

Slide 37

Queries: Result “data”: { “author”: { “id”: “MXxBdXRob3J8ZjA”, “name”: “Anne McCaffrey”, “books”: { “totalCount”: 6, “edges”: [ { “node”: { “id”: “MXxCb29rfGYwNzU”, “title”: “Dragonflight” } }, Rob Allen @akrabat @rob@akrabat.com

Slide 38

Slide 38

Queries: Result “data”: { “author”: { “id”: “MXxBdXRob3J8ZjA”, “name”: “Anne McCaffrey”, “books”: { “totalCount”: 6, “edges”: [ { “node”: { “id”: “MXxCb29rfGYwNzU”, “title”: “Dragonflight” } }, Rob Allen @akrabat @rob@akrabat.com

Slide 39

Slide 39

Queries: Result “data”: { “author”: { “id”: “MXxBdXRob3J8ZjA”, “name”: “Anne McCaffrey”, “books”: { “totalCount”: 6, “edges”: [ { “node”: { “id”: “MXxCb29rfGYwNzU”, “title”: “Dragonflight” } }, Rob Allen @akrabat @rob@akrabat.com

Slide 40

Slide 40

Mutations mutation { createAuthor( name: “Mary Shelley”, dateOfBirth: “1797-08-30” ) { returning { id, name } } } Rob Allen @akrabat @rob@akrabat.com

Slide 41

Slide 41

Mutations mutation { createAuthor( name: “Mary Shelley”, dateOfBirth: “1797-08-30” ) { returning { id, name } } } Rob Allen @akrabat @rob@akrabat.com

Slide 42

Slide 42

Mutations mutation { createAuthor( name: “Mary Shelley”, dateOfBirth: “1797-08-30” ) { returning { id, name } } } Rob Allen @akrabat @rob@akrabat.com

Slide 43

Slide 43

Mutations mutation { createAuthor( name: “Mary Shelley”, dateOfBirth: “1797-08-30” ) { returning { id, name } } } Rob Allen @akrabat @rob@akrabat.com

Slide 44

Slide 44

Mutations: Response Response: “data”: { “createAuthor”: { “returning”: [ { “id”: “e3388cbea4e840a”, “name”: “Mary Shelly”, } ] } } Rob Allen @akrabat @rob@akrabat.com

Slide 45

Slide 45

Which to pick? Rob Allen @akrabat @rob@akrabat.com

Slide 46

Slide 46

Lamborghini or Ferrari? Rob Allen @akrabat @rob@akrabat.com

Slide 47

Slide 47

Lamborghini or Truck? Rob Allen @akrabat @rob@akrabat.com

Slide 48

Slide 48

Considerations • What is it to be used for? • Response customisation requirements • HTTP interoperability requirements Rob Allen @akrabat @rob@akrabat.com

Slide 49

Slide 49

API Uses • Do you control both server and client? • How many users are expected? • What is the skill level of your integrators? Rob Allen @akrabat @rob@akrabat.com

Slide 50

Slide 50

Response customisation • GraphQL is a query-first language • REST tends towards less customisation • With RPC you get what you’re given! (None will fix your database layer’s ability to efficiently retreive the data requested!) Rob Allen @akrabat @rob@akrabat.com

Slide 51

Slide 51

Performance • REST and RPC puts server performance first • GraphQL puts client performance first Rob Allen @akrabat @rob@akrabat.com

Slide 52

Slide 52

Caching • GraphQL and RPC can only cache at application layer • REST can additionally cache at HTTP layer Rob Allen @akrabat @rob@akrabat.com

Slide 53

Slide 53

Data Transfer GraphQL: query { avatar(userId: “1234”) } { “data”: { “avatar”: “(base64 data)” “format”: “image/jpeg” } RPC: POST /api { “method”: “getAvatar”, “userId”: “1234” } { “result”: “(base64 data)” } }} Rob Allen @akrabat @rob@akrabat.com

Slide 54

Slide 54

Data Transfer REST: REST: GET /user/1234/avatar Accept: image/jpeg GET /user/1234/avatar Accept: application/json HTTP/1.1 200 OK {jpg image data} HTTP/1.1 200 OK {“data”: “(base64 data)”} Rob Allen @akrabat @rob@akrabat.com

Slide 55

Slide 55

Versioning • RPC, GraphQL and REST can all version via evolution as easily as each other Rob Allen @akrabat @rob@akrabat.com

Slide 56

Slide 56

Versioning • RPC, GraphQL and REST can all version via evolution as easily as each other • GraphQL is very good for deprecation of specific fields Rob Allen @akrabat @rob@akrabat.com

Slide 57

Slide 57

Design considerations It’s always hard! Rob Allen @akrabat @rob@akrabat.com

Slide 58

Slide 58

Design considerations It’s always hard! Rob Allen @akrabat @rob@akrabat.com

Slide 59

Slide 59

It’s your choice Rob Allen @akrabat @rob@akrabat.com

Slide 60

Slide 60

Developer Experience Rob Allen @akrabat @rob@akrabat.com

Slide 61

Slide 61

Correctness Rob Allen @akrabat @rob@akrabat.com

Slide 62

Slide 62

Correctness RPC: Functions! Rob Allen @akrabat @rob@akrabat.com

Slide 63

Slide 63

Correctness RPC: Functions! REST: HTTP matters! Rob Allen @akrabat @rob@akrabat.com

Slide 64

Slide 64

Correctness RPC: Functions! REST: HTTP matters! GraphQL: Think in terms of relationships! Rob Allen @akrabat @rob@akrabat.com

Slide 65

Slide 65

Correctness RPC: Functions! REST: HTTP matters! GraphQL: Think in terms of relationships! Rob Allen @akrabat @rob@akrabat.com

Slide 66

Slide 66

Errors Rob Allen @akrabat @rob@akrabat.com

Slide 67

Slide 67

REST Errors HTTP/1.1 503 Service Unavailable Content-Type: application/problem+json Content-Language: en { “status”: 503, “type”: “https://example.com/service-unavailable”, “title”: “Could not authorise user.”, “detail”: “Auth service is down for maintenance.”, “instance”: “https://example.com/maintenance/2023-02-15”, “error_code”: “AUTHSERVICE_UNAVAILABLE” } Rob Allen @akrabat @rob@akrabat.com

Slide 68

Slide 68

GraphQL Errors • • • • • Always returns 200, unless infrastructure failure Common to see cryptic messages from GraphQL service Top level ‘errors’ key for exceptional scenarios Domain errors should be within the schema Consider using an error type per node and a union: union CreateUserResult = UserCreated | UserCreationErrors Rob Allen @akrabat @rob@akrabat.com

Slide 69

Slide 69

Documentation Rob Allen @akrabat @rob@akrabat.com

Slide 70

Slide 70

API Reference • GraphQL: Built-in introspection • REST: OpenAPI Specification Both allow generation of a API reference website. Rob Allen @akrabat @rob@akrabat.com

Slide 71

Slide 71

Tutorials The API Reference is the what, the tutorials are the how and why Rob Allen @akrabat @rob@akrabat.com

Slide 72

Slide 72

GitHub GraphQL Rob Allen @akrabat @rob@akrabat.com

Slide 73

Slide 73

GitHub REST Rob Allen @akrabat @rob@akrabat.com

Slide 74

Slide 74

To sum up Rob Allen @akrabat @rob@akrabat.com

Slide 75

Slide 75

If you suck at providing a REST API, you will suck at providing a GraphQL API Arnaud Lauret, API Handyman Rob Allen @akrabat @rob@akrabat.com

Slide 76

Slide 76

Thank you! Rob Allen @akrabat @rob@akrabat.com

Slide 77

Slide 77

Photo credits - Architecture: https://www.flickr.com/photos/shawnstilwell/4335732627 - Choose Pill: https://www.flickr.com/photos/eclib/4905907267 - Lamborghini & Ferrari: https://akrab.at/3w0yFmg - Lamborghini & Truck: https://akrab.at/3F4kAZk - ’50s Computer: https://www.flickr.com/photos/9479603@N02/49755349401 - Blackboard: https://www.flickr.com/photos/bryanalexander/17182506391 - Crash Test: https://www.flickr.com/photos/astrablog/4133302216 Rob Allen @akrabat @rob@akrabat.com