The Right API for the Job

A presentation at phpday 2022 in May 2022 in Verona, VR, Italy by Rob Allen

Slide 1

Slide 1

The Right API for the Job Rob Allen PHPDay, May 2022

Slide 2

Slide 2

Fit for Purpose Rob Allen ~ @akrabat

Slide 3

Slide 3

API Architecture Rob Allen ~ @akrabat

Slide 4

Slide 4

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

Slide 5

Slide 5

RPC APIs Rob Allen ~ @akrabat

Slide 6

Slide 6

RPC APIs • Call a function on a remote server Rob Allen ~ @akrabat

Slide 7

Slide 7

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

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

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

Slide 10

Slide 10

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

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

Slide 12

Slide 12

RESTful APIs Rob Allen ~ @akrabat

Slide 13

Slide 13

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

Slide 14

Slide 14

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

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

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

Slide 17

Slide 17

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

Slide 18

Slide 18

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

Slide 19

Slide 19

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

Slide 20

Slide 20

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

Slide 21

Slide 21

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

Slide 22

Slide 22

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

Slide 23

Slide 23

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

Slide 24

Slide 24

GraphQL APIs Rob Allen ~ @akrabat

Slide 25

Slide 25

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

Slide 26

Slide 26

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

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 • Self-describing schema Rob Allen ~ @akrabat

Slide 28

Slide 28

Queries query { author(name: “Ann McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title, datePublished } } } } } Rob Allen ~ @akrabat

Slide 29

Slide 29

Queries query { author(name: “Ann McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title, datePublished } } } } } Rob Allen ~ @akrabat

Slide 30

Slide 30

Queries query { author(name: “Ann McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title, datePublished } } } } } Rob Allen ~ @akrabat

Slide 31

Slide 31

Queries query { author(name: “Ann McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title, datePublished } } } } } Rob Allen ~ @akrabat

Slide 32

Slide 32

Queries query { author(name: “Ann McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title, datePublished } } } } } Rob Allen ~ @akrabat

Slide 33

Slide 33

Queries query { author(name: “Ann McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title, datePublished } } } } } Rob Allen ~ @akrabat

Slide 34

Slide 34

Queries query { author(name: “Ann McCaffrey”) { id, name books(first: 5) { totalCount edges { node { id, title, datePublished } } } } } Rob Allen ~ @akrabat

Slide 35

Slide 35

Queries “data”: { “author”: { “id”: “MXxBdXRob3J8ZjA”, “name”: “Ann McCaffrey”, “books”: { “totalCount”: 6, “edges”: [ { “node”: { “id”: “MXxCb29rfGYwNzU”, “title”: “Dragonflight” } }, Rob Allen ~ @akrabat

Slide 36

Slide 36

Queries “data”: { “author”: { “id”: “MXxBdXRob3J8ZjA”, “name”: “Ann McCaffrey”, “books”: { “totalCount”: 6, “edges”: [ { “node”: { “id”: “MXxCb29rfGYwNzU”, “title”: “Dragonflight” } }, Rob Allen ~ @akrabat

Slide 37

Slide 37

Queries “data”: { “author”: { “id”: “MXxBdXRob3J8ZjA”, “name”: “Ann McCaffrey”, “books”: { “totalCount”: 6, “edges”: [ { “node”: { “id”: “MXxCb29rfGYwNzU”, “title”: “Dragonflight” } }, Rob Allen ~ @akrabat

Slide 38

Slide 38

Queries “data”: { “author”: { “id”: “MXxBdXRob3J8ZjA”, “name”: “Ann McCaffrey”, “books”: { “totalCount”: 6, “edges”: [ { “node”: { “id”: “MXxCb29rfGYwNzU”, “title”: “Dragonflight” } }, Rob Allen ~ @akrabat

Slide 39

Slide 39

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

Slide 40

Slide 40

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

Slide 41

Slide 41

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

Slide 42

Slide 42

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

Slide 43

Slide 43

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

Slide 44

Slide 44

Which to pick? Rob Allen ~ @akrabat

Slide 45

Slide 45

Lamborghini or Ferrari? Rob Allen ~ @akrabat

Slide 46

Slide 46

Lamborghini or Truck? Rob Allen ~ @akrabat

Slide 47

Slide 47

Considerations • • • • What is it to be used for? Response customisation requirements HTTP interoperability requirements Binary protocol? Rob Allen ~ @akrabat

Slide 48

Slide 48

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

Slide 49

Slide 49

Performance • REST and RPC puts server performance first • GraphQL puts client performance first Rob Allen ~ @akrabat

Slide 50

Slide 50

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

Slide 51

Slide 51

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

Slide 52

Slide 52

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

Slide 53

Slide 53

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

Slide 54

Slide 54

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

Slide 55

Slide 55

Design considerations It’s always hard! Rob Allen ~ @akrabat

Slide 56

Slide 56

Design considerations It’s always hard! Rob Allen ~ @akrabat

Slide 57

Slide 57

It’s your choice Rob Allen ~ @akrabat

Slide 58

Slide 58

Developer Experience Rob Allen ~ @akrabat

Slide 59

Slide 59

Correctness Rob Allen ~ @akrabat

Slide 60

Slide 60

Correctness RPC: Functions! Rob Allen ~ @akrabat

Slide 61

Slide 61

Correctness RPC: Functions! REST: HTTP matters! Rob Allen ~ @akrabat

Slide 62

Slide 62

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

Slide 63

Slide 63

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

Slide 64

Slide 64

Errors Rob Allen ~ @akrabat

Slide 65

Slide 65

Errors Error representations must be first class citizens Rob Allen ~ @akrabat

Slide 66

Slide 66

Errors Error representations must be first class citizens Rob Allen ~ @akrabat

Slide 67

Slide 67

Documentation Rob Allen ~ @akrabat

Slide 68

Slide 68

Documentation • API Reference Rob Allen ~ @akrabat

Slide 69

Slide 69

Documentation • API Reference • Tutorials Rob Allen ~ @akrabat

Slide 70

Slide 70

To sum up Rob Allen ~ @akrabat

Slide 71

Slide 71

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

Slide 72

Slide 72

Thank you! https://joind.in/talk/8cdd9 Rob Allen ~ @akrabat

Slide 73

Slide 73

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