Upgrade to Pro — share decks privately, control downloads, hide ads and more …

API Pain Points - PHP Argentina 2014

API Pain Points - PHP Argentina 2014

A look at some ways to avoid doing dumb things with your API that will haunt you later.

Phil Sturgeon

November 07, 2014
Tweet

More Decks by Phil Sturgeon

Other Decks in Programming

Transcript

  1. A P I PA I N - P O I

    N T S G E T T I N G T H I N G S W R O N G F O R F U N A N D P R O F I T @ P H I L S T U R G E O N # P H P C O N FA R
  2. A R C H I T E C T U

    R E O L D S C H O O L
  3. D ATA B A S E S E E D

    I N G L E A V E Y O U R C U S T O M E R S A L O N E
  4. E N D P O I N T T H

    E O RY N A M I N G T H I N G S I S H A R D
  5. P L U R A L V S I N

    G U L A R ? C O N S I S T E N C Y I S K I N G /user/23 /users
  6. P L U R A L V S I N

    G U L A R ? C O N S I S T E N C Y I S K I N G /opportunity/43 /opportunities
  7. P L U R A L V S I N

    G U L A R ? C O N S I S T E N C Y I S K I N G /person/dave /people
  8. P L U R A L V S I N

    G U L A R ? C O N S I S T E N C Y I S K I N G /places /places/12 /places/12/checkins /places/12/checkins/34 /checkins/34
  9. N O N E E D F O R S

    E O Q U E RY S T R I N G S A R E F I N E /users/active/true /users?active=true
  10. A U T O - I N C R E

    M E N T = B A D C T R L + S Y O U R W E B S I T E /checkins/1 /checkins/2 /checkins/2369 … /checkins/3
  11. A U T O - I N C R E

    M E N T = B A D C T R L + S Y O U R W E B S I T E github.com/zackkitzmiller/tiny-php $tiny = new \ZackKitzmiller\Tiny('lDpuU74QNH6B'); ! echo $tiny->to(5); // E ! echo $tiny->from('E'); // 5
  12. A U T O - I N C R E

    M E N T = B A D C T R L + S Y O U R W E B S I T E ! use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\Exceptio ! $uuid4 = Uuid::uuid4(); ! echo $uuid4; // 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a github.com/ramsey/uuid
  13. W H I C H M E T H O

    D S V E R B S O U P List GET /users Read GET /users/X Update PUT /users/X Update PATCH /users/X Create POST /users Delete DELETE /users/X Image PUT /users/X/image Images POST /users/X/images Favourites GET /users/X/images
  14. H T T P V E R B S M

    AT T E R H O N E S T LY Dont be @jamiehannaford. That sounds like a bad day.
  15. P I C K T H E R I G

    H T F O R M AT B E F O R E Y O U S E T O U T
  16. F O R M PAY L O A D S

    J U S T S E N D J S O N foo=something&bar[baz]=thing &bar[stuff]=junk&bar=true 23
  17. H A C K Y PAY L O A D

    S N O T L I K E T H A T
  18. R E A L J S O N PAY L

    O A D S T H N X !
  19. R E A D I N G R E A

    L D ATA I S E A S Y T H E H T T P WA Y Lazy $_POST[‘foo’]; Proper json_decode(file_get_contents(‘php://input')); Proper in Laravel Input::json(‘foo’);
  20. E R R O R M E S S A

    G E S B E I N G W R O N G C O R R E C T LY http://www.funcage.com/blog/page/439/
  21. 2 0 0 I S N O T T H

    E O N LY S U C C E S S K N O W Y O U R C O D E S if ($statusCode != 200) { throw new Exception('AAGHH!!'); }
  22. 2xx is all about success 3xx is all about redirection

    4xx is all about client errors 5xx is all about service errors
  23. 200 - Generic everything is OK 201 - Created something

    OK 202 - Accepted but is being processed async 400 - Bad Request (Validation?) 401 - Unauthorized 403 - Current user is forbidden 404 - That URL is not a valid route 405 - Method Not Allowed 410 - Data has been deleted, deactivated, suspended, etc 500 - Something unexpected happened and it is the APIs fault 503 - API is not here right now, please try again later
  24. C L E A R , H U M A

    N E R R O R S W H A T H A P P E N E D { "error": { "errors": [ { "domain": "youtube.parameter", "reason": "missingRequiredParameter", "message": "No filter selected.", "locationType": "parameter", "location": "" } ], "code": 400, "message": "No filter selected." } }
  25. E R R O R S S H O U

    L D M A K E S E N S E W H A T H A P P E N E D &mine=true "reason": "missingRequiredParameter", "message": "No filter selected.", … WTF
  26. S U P P L E M E N T

    H T T P C O D E S W H A T H A P P E N E D { "error": { "type": "OAuthException", "message": "Session has expired at unix time 1385243766. The current unix time is 1385848532" } }
  27. S U P P L E M E N T

    H T T P C O D E S W H A T H A P P E N E D { "error": { "message": "(#210) Subject must be a page.", "type": "OAuthException", "code": 210 } }
  28. S U P P L E M E N T

    H T T P C O D E S W H A T H A P P E N E D { "error": { "message": "(#210) Subject must be a page.", "type": "OAuthException", "code": 210, "url": “http://developers.facebook.com/errors#210“ } }
  29. O A U T H 2 C A N D

    O A L O T PA S S W O R D S , I M P L I C I T, S O C I A L L O G I N S …
  30. FA C E B O O K … Y O

    U B # % @ * D S ! ! ! S E R I O U S LY Refresh Tokens? ! Lol
  31. Y O U T U B E … Y O

    U S E M I - B # % @ * D S ! ! ! S T I L L S E R I O U S LY Refresh Tokens? ! Kinda
  32. P R E S E N TAT I O N

    L AY E R D O N T L E T U S E R S B E H I N D T H E C U R TA I N
  33. ! return Places::all(); P R E S E N TAT

    I O N L AY E R D O N T L E T U S E R S B E H I N D T H E C U R TA I N
  34. T R A N S F O R M E

    R S … A S S E M B L E ! public function transform(Book $book) { return [ 'id' => (int) $book->id, 'title' => $book->title, 'year' => $book->yr, ‘created' => (string) $book->created_at, ]; } fractal.thephpleague.com
  35. F L E X I B L E R E

    S P O N S E S S T O P Y O U R I P H O N E D E V C O M P L A I N I N G GET /checkins/dsfXte ?include=place,user,activity
  36. PA G I N AT E D A TA G

    R O W S FA S T { "data": [ ... ], "cursors": { "after": "MTI=", "next_url": "https://api.example.com/places ?cursor=MTI%3" } }
  37. D E F I N E A L I M

    I T R A N G E PA G I N A T I O N D D O S if ($limit < 1 || $limit > 100) { $limit = 100; }
  38. A U T O M AT E T E S

    T I N G I F Y O U L O V E Y O U R J O B http://www.engineersgotblued.com/
  39. P H P U N I T + B E

    H AT http://www.bil-jac.com/bestfriendsclub.php
  40. Scenario: Find a merchant When I request "GET /moments/1" Then

    I get a "200" response And scope into the "data" property And the properties exist: """ id title year created """
  41. Scenario: Try to find an ` checkin When I request

    "GET /checkins/nope" Then I get a "404" response
  42. Scenario:Wrong Arguments for user follow Given I have the payload:

    """ {"is_following": "foo"} """ When I request "PUT /users/1” Then I get a "400" response Not a boolean
  43. V E R S I O N I N G

    / V 1 / D O E S N T C O U N T https://api.example.com/v1/places
  44. V E R S I O N I N G

    / V 1 / D O E S N T C O U N T https://api-v1.example.com/places
  45. V E R S I O N I N G

    / V 1 / D O E S N T C O U N T Accept: application/vnd.example+json; version=1 Accept: application/vnd.example+json; version=2
  46. V E R S I O N I N G

    / V 1 / D O E S N T C O U N T Accept: application/vnd.example.user+json; version=1 Accept: application/vnd.example.user+json; version=2
  47. V E R S I O N I N G

    / V 1 / D O E S N T C O U N T Copy Facebook ! Maybe? ! THIS ONE TIME! Facebook ruined the one good thing they ever did
  48. E V E RY T H I N G I

    S W R O N G D O N T B E T H A T G U Y troyhunt.com/2014/02/your-api-versioning-is-wrong-which-is.html