Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

A bird's eye view on API development

239 views

Published on

As given at LaravelLive India:

We all know how to develop an API right? You just churn out a bit of JSON and call it a day... In this talk we're going to dig just a bit deeper then that. How do I choose HTTP codes, when should I use what verb, how do I structure endpoints, and what is this HATEOAS thing? After we've covered the basics, we'll move on to more advanced topics such as authentication, versioning, and custom headers.

Published in: Software
  • Be the first to comment

  • Be the first to like this

A bird's eye view on API development

  1. 1. Birds eye view on: API DEVELOPMENT
  2. 2. WHO ? Frederick Vanbrabant Software engineer madewithlove
  3. 3. Dries Vints @driesvints Freek Van der Herten @freekmurze phpantwerp.be
  4. 4. { "id": 1, "title": "7 Things You Should NEVER Do to a potato", "subtitle": "you will never believe nr 4", "body": "Some body copy that will go on in great detail", "comments": [{ "id": 1, "body": "woah this changed my life" }, { "id": 2, "body": "I will never look at stuff in the same way" }] } GET /getblogpost/1
  5. 5. Why is this not so great ? Url is kinda structure less What if we get loads of articles? What if we get loads of comments? Damn, we need to write documentation Is this the best way to pinpoint a resource
  6. 6. GET /getblogposts/1 Let's look at that endpoint HTTP verb Endpoint
  7. 7. HTTP verbs
  8. 8. HTTP verbs HTTP != CRUD
  9. 9. HTTP verbs Verb Return HTTP Code POST 201 Sends a payload to the server, Returns an empty body.
  10. 10. HTTP verbs Verb Return HTTP Code POST 201 POST /posts { "title": "Why cheese is better then real friends", "body": "People only stand in the way of you and your cheese!" } Post body
  11. 11. HTTP verbs Verb Return HTTP Code GET 200 Does not send a payload Returns a collection of or a single resource
  12. 12. HTTP verbs Verb Return HTTP Code GET 200 GET /posts/2 { "title": "How to fake your own death", "body": "You can buy cheese with the insurance money!" } Return body
  13. 13. HTTP verbs Verb Return HTTP Code PUT 204 Updates a resource (needs the entire object) Returns an empty body.
  14. 14. HTTP verbs Verb Return HTTP Code PUT 204 PUT /posts/2 { "title": "Help I'm stuck in a keynote making factory", "body": "Send cheese!" } Put body
  15. 15. HTTP verbs Verb Return HTTP Code PATCH 200 Accepts instructions to update the resource Returns the resource
  16. 16. Wait what? Accepts instructions to update the resource returns the resource PATCH /artists/kanye/ [ { "op": "replace", "path": "artists/kanye/cars", "value": 7 }, ]
  17. 17. Wait what? Accepts instructions to update the resource returns the resource PATCH /artists/kanye [ {"cars" : 7} ] Content-Type: application/partial-update-json
  18. 18. HTTP verbs Verb Return HTTP Code DELETE 204 Removed the resource Returns an empty body.
  19. 19. HTTP verbs Verb Return HTTP Code DELETE 204 DELETE /posts/1
  20. 20. HTTP CODE
  21. 21. HTTP CODE Range 1XX - Information Code What it means 100 continue 101 Switching Protocols 102 Processing
  22. 22. HTTP CODE Range 2XX - Success Code What it means 200 Ok 201 Created 202 Accepted
  23. 23. HTTP CODE Range 3XX - Redirection Code What it means 301 Moved 300 Multiple Choices
  24. 24. HTTP CODE Range 4XX - Client error Code What it means 400 Bad Request 401 Unauthorized 404 Not found
  25. 25. HTTP CODE Range 5XX - Server error Code What it means 500 Internal Server Error 503 Service Unavailable 504 Gateway Timeout
  26. 26. HTTP HEADERS
  27. 27. HTTP HEADERS Send on each request and response Meta data to the call Can define custom headers
  28. 28. HTTP HEADERS GET / HTTP/1.1 Host: www.google.com Connection: keep-alive Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KH X-Chrome-UMA-Enabled: 1 X-Client-Data: CIS2yQEIpbbJAQjEtskBCOCUygEI+pjKAQjznMoB Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Encoding: gzip, deflate, sdch Accept-Language: nl,en;q=0.8 Cookie: *Cookie data* Request
  29. 29. HTTP HEADERS Status: 200 (OK) Date: Fri, 08 Jul 2016 13:59:05 GMT Expires: -1 Cache-Control: private, max-age=0 Content-Type: text/html; charset=ISO-8859-1 X-Xss-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN Set-Cookie: NID=81=x8aqWN0zsVHK2QcLEZca6603H8BYJxXP6bfjQl0cT82iM4j7fE3V9wH2qbpXW0D Accept-Ranges: none Vary: Accept-Encoding Transfer-Encoding: chunked *HTML, JSON, XML OR WHATEVER* Response
  30. 30. What about the endpoint GET /getblogposts/1
  31. 31. What about the endpoint GET /posts/1
  32. 32. What about the endpoint GET /posts/1 Nouns are good, verbs are bad Use plurals
  33. 33. What about the endpoint GET /posts/1 GET /posts/1/comments GET /posts/1/comments/15 OR GET /comments/15
  34. 34. What about the endpoint GET /posts GET /posts/slugs-are-allowed
  35. 35. What about the endpoint GET users/4b3403665fea6/posts/4b340550242239
  36. 36. What about the endpoint Endpoint structure != database structure
  37. 37. We still 200 ?
  38. 38. Let's check out that body? { "id": 1, "title": "7 Things You Should NEVER Do to a potato", "subtitle": "you will never believe nr 4", "body": "Some body copy that will go on in great detail", "comments": [{ "id": 1, "body": "woah this changed my life" }, { "id": 2, "body": "I will never look at stuff in the same way" }] }
  39. 39. Let's use a standard Battle tested and growing up to be the standard
  40. 40. { "count": 87, "next": "http://swapi.co/api/people/?page=2", "previous": null, "results": [ { "name": "Luke Skywalker", "height": "172", "mass": "77", "hair_color": "blond", "skin_color": "fair", "eye_color": "blue", "birth_year": "19BBY", "gender": "male", "homeworld": "http://swapi.co/api/planets/1/", "films": [ "http://swapi.co/api/films/6/", "http://swapi.co/api/films/3/", "http://swapi.co/api/films/2/", "http://swapi.co/api/films/1/", "http://swapi.co/api/films/7/" ], "species": [ "http://swapi.co/api/species/1/" ], "vehicles": [ "http://swapi.co/api/vehicles/14/", "http://swapi.co/api/vehicles/30/" ], "starships": [ "http://swapi.co/api/starships/12/", "http://swapi.co/api/starships/22/" ], "created": "2014-12-09T13:50:51.644000Z", "edited": "2014-12-20T21:17:56.891000Z", "url": "http://swapi.co/api/people/1/"
  41. 41. { "count": 87, "next": "http://swapi.co/api/people/?page=3", "previous": "http://swapi.co/api/people/?page=1", "results": [ .... ] } Links ? page-based
  42. 42. { "count": 30, "next": "http://swapi.co/api/people/?offset=60&limit=30", "previous": "http://swapi.co/api/people/?offset=0&limit=30", "results": [ .... ] } Links ? offset-based
  43. 43. { "count": 87, "next": "http://swapi.co/api/people/?cursor=1374004777531007833", "previous": "http://swapi.co/api/people/?cursor=2627305797328905258", "results": [ .... ] } Links ? cursor-based
  44. 44. { "name": "Luke Skywalker", "height": "172", "mass": "77", "hair_color": "blond", "skin_color": "fair", "eye_color": "blue", "birth_year": "19BBY", "gender": "male", "homeworld": "http://swapi.co/api/planets/1/", "films": [ "http://swapi.co/api/films/6/", "http://swapi.co/api/films/3/", "http://swapi.co/api/films/2/", "http://swapi.co/api/films/1/", "http://swapi.co/api/films/7/" ], "species": [ "http://swapi.co/api/species/1/" ], "vehicles": [ "http://swapi.co/api/vehicles/14/", "http://swapi.co/api/vehicles/30/" ], "starships": [ "http://swapi.co/api/starships/12/", "http://swapi.co/api/starships/22/" ], "created": "2014-12-09T13:50:51.644000Z", "edited": "2014-12-20T21:17:56.891000Z", "url": "http://swapi.co/api/people/1/" }
  45. 45. Wait I can't have nested- resources?
  46. 46. Wait I can't have nested- resources? This is not really HTTP now is it ?
  47. 47. Think about how you surf the web That's pretty nice right ?
  48. 48. HATEOAS Hypermedia as the Engine of Application State
  49. 49. HATEOAS Hypermedia as the Engine of Application State { "name": "Boba Fett", "height": "183", "mass": "78.2", "hair_color": "black", "skin_color": "fair", "eye_color": "brown", "birth_year": "31.5BBY", "gender": "male", "homeworld": "http://swapi.co/api/planets/10/", "films": [ "http://swapi.co/api/films/5/", "http://swapi.co/api/films/3/", "http://swapi.co/api/films/2/" ], "species": [ "http://swapi.co/api/species/1/" ], "vehicles": [], "starships": [ "http://swapi.co/api/starships/21/" ], "created": "2014-12-15T12:49:32.457000Z", "edited": "2014-12-20T21:17:50.349000Z", "url": "http://swapi.co/api/people/22/"
  50. 50. HATEOAS "I'm not going to make 500 calls just to get some comments"
  51. 51. HATEOAS "I'm not going to make 500 calls just to get some comments" GET /films GET /films/4,5,6
  52. 52. HATEOAS "Can't you just add the resources to the url?" GET /articles/1?include=comments,likes
  53. 53. QUERY PARAMETERS Filter the response to what's valid on the query GET /cheeses?type=brie,cheddar GET /cheeses?type[]=brie&type[]=cheddar
  54. 54. AUTH
  55. 55. AUTH
  56. 56. AUTH - HTTP Basic - JWT - OAuth 2.0
  57. 57. HTTP Basic - Super easy - Not super safe
  58. 58. JWT (Json web tokens) - No database hassle - Needs some knowledge
  59. 59. JWT (Json web tokens) ServerClient make new calls with the token Return token Send credentials
  60. 60. JWT (Json web tokens) https://jwt.io/
  61. 61. OAuth2 - Very secure and very flexible - Can be daunting to setup
  62. 62. OAuth2 ServerClient make new calls with the token Return token + Refresh token Send credentials
  63. 63. OAuth2 ServerClient make new calls with the token Return token + Refresh token Send refresh token
  64. 64. API VERSIONING
  65. 65. API VERSIONING YOU SHOULD NOT HAVE TO VERSION AN API!
  66. 66. API VERSIONING BUT YOU WILL HAVE TO EVENTUALLY
  67. 67. API VERSIONING GET /api/v1/artists/taylor-swift
  68. 68. API VERSIONING GET /api/v1/artists/taylor-swift The good The bad Easy to implement Routes should not change Easy to see what version we are on Meta data should be in a header
  69. 69. API VERSIONING GET /api/artists/taylor-swift x-api-version: 1
  70. 70. API VERSIONING The good The bad Meta data is in the header Custom header ... ? Url does not change You need documentation Url does not change GET /api/artists/taylor-swift x-api-version: 1
  71. 71. API VERSIONING GET /api/artists/taylor-swift Accept: application/vnd.website.v1+json
  72. 72. API VERSIONING The good The bad Meta data is in the header Harder to test Standard http header You need documentation GET /api/artists/taylor-swift Accept: application/vnd.website.v1+json
  73. 73. Random TIPS START WITH DOCUMENTATION
  74. 74. Random TIPS LOOK AT THE USER FIRST, NOT THE TECH (A GOOD API DOES NOT NEED TO BE REST)
  75. 75. Random TIPS TYPE CAST YOUR RETURN VALUES
  76. 76. Random TIPS CONSISTENCY IS KING
  77. 77. Random TIPS TEST YOUR ENDPOINTS
  78. 78. Random TIPS NEVER TRUST YOUR USERS
  79. 79. Random TIPS Use PHP? Laravel: https://github.com/dingo/api Vanilla: https://thephpleague.com https://github.com/spatie Use Python? Django: http://www.django-rest-framework.org
  80. 80. Random TIPS Want to know more? This talks in text form: https://blog.madewithlove.be/post/birdseye-view-on-api Phil Sturgeon's book: https://leanpub.com/build-apis-you-wont-hate Great O'Reily book RESTful Web APIs: http://shop.oreilly.com/product/0636920028468.do
  81. 81. Questions! Twitter: TheEdonian
  82. 82. THANKS !

×