Slide 1

Slide 1 text

API STANDARDS 2.0

Slide 2

Slide 2 text

HELLO! I 'm Michael I'm @mheap on Twitter I have a favourite Time Zone (DMT)

Slide 3

Slide 3 text

API STANDARDS 2.0

Slide 4

Slide 4 text

API STANDARDS 2.0 AN OPINIONATED GUIDE TO

Slide 5

Slide 5 text

5

Slide 6

Slide 6 text

APIs at Nexmo 6 REST-like

Slide 7

Slide 7 text

APIs at Nexmo 7 Pragmatic REST-like

Slide 8

Slide 8 text

APIs at Nexmo 8 Pragmatic REST-like Consumer Success

Slide 9

Slide 9 text

API Standards 9 Status Codes

Slide 10

Slide 10 text

API Standards 10 HTTP Verbs Status Codes

Slide 11

Slide 11 text

API Standards 11 HTTP Verbs Status Codes Nouns, not Verbs

Slide 12

Slide 12 text

What we're not going to cover ▸ Message formats ▸ Rate limiting ▸ Content negotiation ▸ HTTP headers ▸ Hypermedia ▸ Resource design ▸ Response design ▸ RPC endpoints ▸ Documentation ▸ Asynchronous actions ▸ Idempotency ▸ Caching ▸ API Gateways ▸ Security ▸ GraphQL ▸ Available RFCs 12

Slide 13

Slide 13 text

1. Errors Status Codes, RFC7807 + Extensions 13

Slide 14

Slide 14 text

2. Versioning Header/URL, Versioning Schemes, Deprecation 14

Slide 15

Slide 15 text

3. Collection Management Sorting, Filtering, Searching, Pagination 15

Slide 16

Slide 16 text

4. URI Design Subresources, Action endpoints 16

Slide 17

Slide 17 text

1. Errors Status Codes, RFC7807 + Extensions 17

Slide 18

Slide 18 text

“ Errors are easy! People should just use status codes

Slide 19

Slide 19 text

401 Unauthorized Error Design 19

Slide 20

Slide 20 text

401 Unauthorized { "error": "No credentials provided" } Error Design 20

Slide 21

Slide 21 text

401 Unauthorized { "error": "Invalid credentials" } Error Design 21

Slide 22

Slide 22 text

401 Unauthorized { "error": "Invalid credentials", "more_help": "http://example.com/ auth#invalid-credentials" } Error Design 22

Slide 23

Slide 23 text

401 Unauthorized { "msg": "Invalid credentials" } Error Design 23

Slide 24

Slide 24 text

401 Unauthorized { "errorCode": 118118, "errorMessage": "Invalid credentials" } Error Design 24

Slide 25

Slide 25 text

401 Unauthorized "Invalid credentials" Error Design 25

Slide 26

Slide 26 text

RFC7807 Type A URI reference that identifies the problem type. When followed, it provides human-readable documentation for the problem type Title A short, human-readable summary of the problem type Detail A human- readable explanation specific to this occurrence of the problem 26 Instance A URI reference that identifies the specific occurrence of the problem

Slide 27

Slide 27 text

RFC7807 Type A URI reference that identifies the problem type. When followed, it provides human-readable documentation for the problem type Title A short, human-readable summary of the problem type Detail A human- readable explanation specific to this occurrence of the problem 27 Instance A URI reference that identifies the specific occurrence of the problem Status The HTTP status code generated by the origin server for this occurrence of the problem.

Slide 28

Slide 28 text

RFC7807 Type A URI reference that identifies the problem type. When followed, it provides human-readable documentation for the problem type Title A short, human-readable summary of the problem type Detail A human- readable explanation specific to this occurrence of the problem 28 Instance A URI reference that identifies the specific occurrence of the problem

Slide 29

Slide 29 text

{ "type": "https://developer.nexmo.com/api- errors#unauthorized", "title": "Invalid credentials supplied", "detail": "You did not provide correct credentials.", "instance": "797a8f199c45014ab7b08bfe9cc1c12c" } RFC7807 29

Slide 30

Slide 30 text

403 Forbidden { "type": "https://example.com/probs/out-of- credit", "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc" } Extension Members 30

Slide 31

Slide 31 text

403 Forbidden { "type": "https://example.com/probs/out-of-credit", "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": ["/account/12345", "/account/67890"] } Extension Members 31

Slide 32

Slide 32 text

400 Bad Request { "type": "https://developer.nexmo.com/api-errors/account/secret- management#validation", "title": "Bad Request", "detail": "The request failed due to validation errors", "invalid_parameters": [ { "name": "secret", "reason": "must contain 1 upper case character" } ], "instance": "797a8f199c45014ab7b08bfe9cc1c12c" } Extension Members 32

Slide 33

Slide 33 text

401: No Credentials, Invalid Credentials 403: Feature disabled, Exceeded calls-per-second limit 422: Invalid product specified + more! Response Library 33

Slide 34

Slide 34 text

“ As a consumer of the APIs, this has already dramatically reduced the amount of code I have to write for each endpoint, and I can't wait until all endpoints are standardised

Slide 35

Slide 35 text

2. Versioning Header/URL, Versioning Schemes, Deprecation 35

Slide 36

Slide 36 text

“ The reason to make a real REST API is to get evolvability … a "v1" is a middle finger to your API customers, indicating RPC/HTTP (not REST) https://twitter.com/fielding/status/376835835670167552

Slide 37

Slide 37 text

“With a sufficient number of users of an interface, it doesn’t matter what you promised in the interface contracts, all observable behaviors of your class or function or whatnot will be depended upon by somebody. Hyrum's Law

Slide 38

Slide 38 text

Accept: application/vnd.nexmo+json; version=3 URI vs Header 38

Slide 39

Slide 39 text

Accept: application/vnd.nexmo+json; version=3 
 X-Nexmo-Version: 3 URI vs Header 39

Slide 40

Slide 40 text

Accept: application/vnd.nexmo+json; version=3 
 X-Nexmo-Version: 3 https://api.nexmo.com/v3 URI vs Header 40

Slide 41

Slide 41 text

https://api.nexmo.com/v1/calls Global vs Endpoint versioning 41

Slide 42

Slide 42 text

https://api.nexmo.com/v1/calls https://api.nexmo.com/v1/media Global vs Endpoint versioning 42

Slide 43

Slide 43 text

https://api.nexmo.com/v1/calls https://api.nexmo.com/v3/media Global vs Endpoint versioning 43

Slide 44

Slide 44 text

https://api.nexmo.com/v1/calls Versioning Scheme 44

Slide 45

Slide 45 text

https://api.nexmo.com/v1/calls https://api.example.com/2010-04-01 Versioning Scheme 45

Slide 46

Slide 46 text

https://api.nexmo.com/v1/calls https://api.example.com/2010-04-01 https://api.example.com/1.2.3 Versioning Scheme 46

Slide 47

Slide 47 text

https://api.nexmo.com/v3.new- feature/calls Version Variants 47

Slide 48

Slide 48 text

Have a deprecation policy. It doesn't matter what it is, but be consistent. Deprecation Policies 48

Slide 49

Slide 49 text

When the decision has been taken to deprecate an API: • For beta products the deprecation period must be at least 30 days (60 days recommended) • For GA products the deprecation period must be at least 1 year • Warning emails will be sent to the API at regular intervals before the deprecation time • A guide will be supplied to customers explaining how to migrate to the replacement API with the initial deprecation notice. Deprecation Policies: Nexmo 49

Slide 50

Slide 50 text

Use the Sunset Header Sunset: Sat, 31 Dec 2018 23:59:59 GMT Sunset Header 50 https://tools.ietf.org/html/draft-wilde-sunset-header-03

Slide 51

Slide 51 text

Use the Link Header Link: rel="sunset" Link Header 51

Slide 52

Slide 52 text

3. Collection Management Sorting, Filtering, Searching, Pagination 52

Slide 53

Slide 53 text

Sorting 53

Slide 54

Slide 54 text

GET /users? sort_by=email&order_by=asc Sorting 54

Slide 55

Slide 55 text

GET /users?sort_by=email.asc Sorting 55

Slide 56

Slide 56 text

GET /users?sort_by=email.asc &sort_by=status.desc Sorting 56

Slide 57

Slide 57 text

GET /users? sort_by=email.asc,status.desc Sorting 57

Slide 58

Slide 58 text

GET /users?sort_by=+email,-status Sorting 58

Slide 59

Slide 59 text

GET /users?sort_by=+email,-status GET /users? sort_by=email.asc,status.desc Sorting 59

Slide 60

Slide 60 text

Filtering 60

Slide 61

Slide 61 text

Filtering 61 Discrete data e.g. user role Continuous data e.g. subscription expiry time

Slide 62

Slide 62 text

Discrete Data 62 /users?role=admin /orders?shipped=true /calls?status=active

Slide 63

Slide 63 text

Discrete Data 63 /users?role=admin /orders?shipped=true /calls?status=active 403 Forbidden /users?is_fbi_informant=true

Slide 64

Slide 64 text

Discrete Data: JSON API 64 GET /employees? filter[role]=internal&filter[title]= senior

Slide 65

Slide 65 text

Discrete Data: JSON API 65 GET /employees? filter[role]=internal&filter[title]= senior GET /employees? role=internal&title=senior

Slide 66

Slide 66 text

Continuous Data 66

Slide 67

Slide 67 text

Continuous Data 67 GET /orders? start_date=2018-01-01&end- date=2018=01-31

Slide 68

Slide 68 text

Continuous Data 68 GET /orders? start_date=2018-01-01&end- date=2018=01-31 GET /orders? date[gte]=2018-01-01&date[lte]=2018= 01-31

Slide 69

Slide 69 text

Industry Standards 69

Slide 70

Slide 70 text

Industry Standards: SCIM 70 filter=userName eq "bjensen" filter=name.familyName co "O'Malley" filter=userName sw "J" filter=urn:ietf:params:scim:schemas:core: 2.0:User:userName sw "J" filter=title pr filter=meta.lastModified gt "2011-05-13T04:42:34Z" https://tools.ietf.org/html/rfc7644#section-3.4.2.2

Slide 71

Slide 71 text

Searching 71

Slide 72

Slide 72 text

Searching 72 GET /items?q=title:red chair AND price:[10 TO 100]

Slide 73

Slide 73 text

Pagination 73 Offset based Cursor based

Slide 74

Slide 74 text

Pagination: Offset 74 GET /calls?page=3&page_size=100

Slide 75

Slide 75 text

Pagination: Cursor 75 GET /calls GET /calls? cursor=2018-01-19T12:33:51 GET /calls? cursor=2018-01-18T03:00:18

Slide 76

Slide 76 text

Pagination: Links 76 { "_links": { "next": { "href": "/calls?cursor=9274" } } } Link: ; rel="next",

Slide 77

Slide 77 text

4. URI Design Subresources, Action endpoints 77

Slide 78

Slide 78 text

GET /users/1 Subresources 78

Slide 79

Slide 79 text

GET /users/1 GET /users/1/calls Subresources 79

Slide 80

Slide 80 text

GET /users/1 GET /users/1/calls GET /users/1/calls/JSDB-1837A Subresources 80

Slide 81

Slide 81 text

GET /users/1 GET /users/1/calls GET /users/1/calls/JSDB-1837A GET /calls/JSDB-1837A Subresources 81

Slide 82

Slide 82 text

GET /users/1 GET /users/1/calls Subresources 82

Slide 83

Slide 83 text

GET /users/1 GET /users/1/calls GET /calls?user=1 Subresources 83

Slide 84

Slide 84 text

GET /users/1 GET /addresses/33-90210 GET /users/1/addresses/33-90210 Subresources 84

Slide 85

Slide 85 text

GET /users/1 GET /addresses/33-90210 GET /users/1/addresses/33-90210 GET /user_addresses/1-33-90210 Subresources 85

Slide 86

Slide 86 text

POST /machines/1/shutdown Actions 86

Slide 87

Slide 87 text

POST /machines/1/shutdown POST /machines/1/actions/shutdown Actions 87

Slide 88

Slide 88 text

POST /machines/1/shutdown POST /machines/1/actions/shutdown POST /machines/1/action:shutdown Actions 88

Slide 89

Slide 89 text

POST /machines/1/shutdown POST /machines/1/actions/shutdown POST /machines/1/action:shutdown POST /machines/1/actions {"type": "shutdown"} Actions 89

Slide 90

Slide 90 text

POST /machine-shutdown Actions as Resources 90

Slide 91

Slide 91 text

POST /machine-shutdown PUT /article-locks/{article-id} DELETE /article-locks/{article-id} POST /balance-transfer Actions as Resources 91

Slide 92

Slide 92 text

Conclusion

Slide 93

Slide 93 text

What we didn't cover ▸ Message formats ▸ Rate limiting ▸ Content negotiation ▸ HTTP headers ▸ Hypermedia ▸ Resource design ▸ Response design ▸ RPC endpoints ▸ Documentation ▸ Asynchronous actions ▸ Idempotency ▸ Caching ▸ API Gateways ▸ Security ▸ GraphQL ▸ Available RFCs 93

Slide 94

Slide 94 text