GraphQL, REST or RPC? Making the choice!
Rob Allen Appdevcon/Endpointcon, May 2023
Slide 2
APIs can be realised in any style but, which makes the most sense?
Rob Allen
@akrabat
@rob@akrabat.com
Slide 3
RPC APIs
Rob Allen
@akrabat
@rob@akrabat.com
Slide 4
RPC APIs • Call a function on a remote server
Rob Allen
@akrabat
@rob@akrabat.com
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
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
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
JSON-RPC Response: { “jsonrpc”: “2.0”, “id”:1, “result”: {“id”: 1234} }
Rob Allen
@akrabat
@rob@akrabat.com
Slide 9
RESTful APIs
Rob Allen
@akrabat
@rob@akrabat.com
Slide 10
RESTful APIs • Operate on a representation of the state of a resource
Rob Allen
@akrabat
@rob@akrabat.com
Slide 11
RESTful APIs • Operate on a representation of the state of a resource • HTTP native
Rob Allen
@akrabat
@rob@akrabat.com
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
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
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
GraphQL APIs
Rob Allen
@akrabat
@rob@akrabat.com
Slide 16
GraphQL APIs • Retrieve only the data you need on consumer side
Rob Allen
@akrabat
@rob@akrabat.com
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
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
Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen
@akrabat
@rob@akrabat.com
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
Queries query { author(name: “Anne McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title } } } } } Rob Allen
@akrabat
@rob@akrabat.com
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
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
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
Which to pick?
Rob Allen
@akrabat
@rob@akrabat.com
Slide 26
Lamborghini or Ferrari? Rob Allen
@akrabat
@rob@akrabat.com
Slide 27
Lamborghini or Truck? Rob Allen
@akrabat
@rob@akrabat.com
Slide 28
Considerations • What is it to be used for? • Response customisation requirements • HTTP interoperability requirements
Rob Allen
@akrabat
@rob@akrabat.com
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
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
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
Performance • REST and RPC puts server performance first • GraphQL puts client performance first
Rob Allen
@akrabat
@rob@akrabat.com
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
Data Transfer RPC: POST /api { “method”: “getAvatar”, “userId”: “1234” } { “result”: “(base64 data)” }
Rob Allen
@akrabat
@rob@akrabat.com
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
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
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
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
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
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
Versioning • RPC, GraphQL and REST can all version via evolution as easily as each other
Rob Allen
@akrabat
@rob@akrabat.com
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
Design considerations It’s always hard!
Rob Allen
@akrabat
@rob@akrabat.com
Slide 44
Design considerations It’s always hard!
Rob Allen
@akrabat
@rob@akrabat.com
Slide 45
It’s your choice
Rob Allen
@akrabat
@rob@akrabat.com
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