THE MAKING OF A GOOD API ROB ALLEN N I N E T E E N F E E T LT D S L I D E S : H T T P S : / / A K R A B AT. C O M / 5 7 5 7 @akrabat

FIT FOR PURPOSE

F E AT U R E S O F A G O O D A P I • Malleability • Correctness • Error handling • Documentation • Security @akrabat

A GOOD API IS MALLEABLE

D E C O U P L E Y O U R R E P R E S E N TAT I O N @akrabat

HYPERMEDIA • An explorable API • Rename end points at will • Re-home end points on different servers @akrabat

HYPERMEDIA { } “_links”: { “self”: { “href”: “https://api.example.com/orders/523” }, “customer”: { “href”: “https://api.example.com/customers/32” }, “invoice”: { “href”: “https://api.example.com/invoices/873” }, “shippingNote”: { “href”: “https://cdn.example.com/ad8wd4.pdf”, “type”: “application/pdf” } }, “currency”: “GBP”, “status”: “shipped”, “total”: 123.45 @akrabat

A GOOD API IS CORRECT

EMBRACE HTTP VERBS METHOD USED FOR IDEMPOTENT? GET Retrieve data Yes PUT Change data Yes DELETE Delete data Yes PATCH Update data No POST Change data No @akrabat

S TAT U S C O D E S M AT T E R 1xx Informational 2xx Success 3xx Redirection 4xx Client error 5xx Server error @akrabat

MEDIA TYPES • Read Content-Type header to decode incoming data • Honour the Accept header when sending data @akrabat

HANDLING CHANGES • Avoid major new versions • Make changes backwards-compatible • Think about forwards-compatibility @akrabat

A NEW VERSION IS A NEW API • Separate code • Domain or URL path is fine • api.example.com/v2/user • api2.example.com/user • Use Server header for minor and patch info @akrabat

A GOOD API HAS G R E AT E R R O R S

G R E AT E R R O R H A N D L I N G • Error representations are first class citizens • Code for computers; messages for humans • Pretty print for the humans! @akrabat

HTTP PROBLEM (RFC 7807) 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 due to an internal problem.”, “detail”: “The authentication service is down for maintenance.”, “instance”: “https://example.com/maintenance-schedule/2017-06”, “error_code”: “AUTHSERVICE_UNAVAILABLE” @akrabat

A GOOD API IS DOCUMENTED

PROFILE LINKS (RFC 6906) Header: Link: https://www.example.com/docs;rel=”profile” Body: { } “_links”: { “profile”: { “href”: “https://www.example.com/docs/” } } @akrabat

H U M A N D O C U M E N TAT I O N • Tutorials • Reference @akrabat

O P E N A P I S P E C I F I C AT I O N • Spec-First API Design • Tooling: https://openapi.tools @akrabat

A GOOD API IS SECURE

OAUTH 2 • Application identification • User identification • User’s trust relationship is with the API @akrabat

R AT E L I M I T HTTP/1.1 429 Too Many Requests Content-Type: application/problem+json X-RateLimit-Limit: 5000 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1471549573 { } “status”: 429, “type”: “https://dev.example.com/rate_limits”, “title”: “API rate limited exceeded.”, “error_code”: “RATE_LIMIT_EXCEEDED” @akrabat

TO SUM UP

THANK YOU HTTPS://JOIND.IN/EVENT/DUTCH-PHP-CONFERENCE-2019 ROB ALLEN @akrabat