GraphQL, REST or RPC? Making the choice!

A presentation at SymfonyCon in December 2024 in Vienna, Austria by Rob Allen

Slide 1

Slide 1

GraphQL, REST or RPC? Making the choice! Rob Allen SymfonyCon, December 2024

Slide 2

Slide 2

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

Slide 3

Slide 3

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

Slide 4

Slide 4

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

Slide 5

Slide 5

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

Slide 6

Slide 6

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

Slide 7

Slide 7

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

Slide 8

Slide 8

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

Slide 9

Slide 9

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

Slide 10

Slide 10

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

Slide 11

Slide 11

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

Slide 12

Slide 12

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

Slide 13

Slide 13

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

Slide 14

Slide 14

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/1234” } } Rob Allen @akrabat @rob@akrabat.com

Slide 15

Slide 15

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

Slide 16

Slide 16

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

Slide 17

Slide 17

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 18

Slide 18

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

Slide 19

Slide 19

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

Slide 20

Slide 20

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

Slide 21

Slide 21

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

Slide 22

Slide 22

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 23

Slide 23

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 24

Slide 24

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 25

Slide 25

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

Slide 26

Slide 26

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

Slide 27

Slide 27

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

Slide 28

Slide 28

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

Slide 29

Slide 29

What is it to be used for? • 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 30

Slide 30

Response customisation • GraphQL is a query-first language • REST tends towards less customisation • With RPC you get what you’re given! Rob Allen @akrabat @rob@akrabat.com

Slide 31

Slide 31

Response customisation • GraphQL is a query-first language • REST tends towards less customisation • With RPC you get what you’re given! (Your data layer’s ability to efficiently retrieve the data is still key!) Rob Allen @akrabat @rob@akrabat.com

Slide 32

Slide 32

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

Slide 33

Slide 33

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

Slide 34

Slide 34

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

Slide 35

Slide 35

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

Slide 36

Slide 36

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

Slide 37

Slide 37

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

Slide 38

Slide 38

Errors • RPC: Returned payload contains an error object of some form • REST: HTTP semantics; status code • GraphQL: Top level error object for Request errors and Field errors Rob Allen @akrabat @rob@akrabat.com

Slide 39

Slide 39

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-05-12”, “error_code”: “AUTHSERVICE_UNAVAILABLE” } Rob Allen @akrabat @rob@akrabat.com

Slide 40

Slide 40

GraphQL Errors “errors”: [ { “message”: “Name for character with ID 7 could not be fetched.”, “path”: [“friends”, 1, “name”] } ], “data”: { “friends”: [ { “id”: “3”, “name”: “F’lar”, “species”: “human”}, { “id”: “7”, “name”: null, “species”: “dragon” }, { “id”: “9”, “name”: “Mnementh”, “species”: “dragon” }, Rob Allen @akrabat @rob@akrabat.com

Slide 41

Slide 41

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

Slide 42

Slide 42

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 43

Slide 43

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

Slide 44

Slide 44

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

Slide 45

Slide 45

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

Slide 46

Slide 46

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 47

Slide 47

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

Slide 48

Slide 48

Photo credits - 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