Get Some REST: Best RESTful API Practices

Get Some REST: Best RESTful API Practices

A handful of pointers for making good RESTful services, or at least avoiding the worst of the pitfalls. Code examples in PHP, this talk was originally given at OSCON 2012

D33d8bdd9096c80b8d1acca8d28410b5?s=128

Lorna Mitchell

July 19, 2012
Tweet

Transcript

  1. Get Some REST: Best RESTful API Practices

  2. About Me 2 • Lorna Jane Mitchell • PHP Consultant/Developer

    • API Specialist • Author of PHP Master • Twitter: @lornajane • Website: http://lornajane.net
  3. About REST 3 • REpresentational State Transfer • Everything is

    a resource • Representations get passed around • Great for data-driven applications
  4. Not RESTful 4 Clues that your service isn’t RESTful: •

    It has a single endpoint
  5. Not RESTful 4 Clues that your service isn’t RESTful: •

    It has a single endpoint • All requests are POSTs
  6. Not RESTful 4 Clues that your service isn’t RESTful: •

    It has a single endpoint • All requests are POSTs • Response metadata is in the body, not header
  7. Not RESTful 4 Clues that your service isn’t RESTful: •

    It has a single endpoint • All requests are POSTs • Response metadata is in the body, not header • There are verbs in the URL
  8. Not RESTful 4 Clues that your service isn’t RESTful: •

    It has a single endpoint • All requests are POSTs • Response metadata is in the body, not header • There are verbs in the URL • The URL includes method names
  9. RESTful != Useful

  10. Best Practices

  11. Use Existing Skills/Tools

  12. Existing Skills 8

  13. MVC Applications 9 Model-View-Controller becomes Model-Controller-Output Handler

  14. MVC Applications 10 Model-View-Controller becomes Model-Controller-Output Handler output controller model

    index
  15. Output Handlers: JSON 11 class JsonView extends ApiView { public

    function render($content) { header('Content-Type: application/json; charset=utf8'); echo $this->buildOutput($content); return true; } /** * Function to build output, can be used by JSON and JSONP */ protected function buildOutput ($content) { $content = $this->addCount($content); $retval = json_encode($content, JSON_NUMERIC_CHECK); return $retval; } }
  16. Meaningful URL Structure

  17. Meaningful URLs 13 What would you expect to find at:

    http://api.joind.in/v2.1/events?filter=upcoming
  18. Meaningful URLs 13 What would you expect to find at:

    http://api.joind.in/v2.1/events?filter=upcoming http://api.joind.in/v2.1/events/853
  19. Meaningful URLs 13 What would you expect to find at:

    http://api.joind.in/v2.1/events?filter=upcoming http://api.joind.in/v2.1/events/853 http://api.joind.in/v2.1/events/853/talks
  20. Meaningful URLs 13 What would you expect to find at:

    http://api.joind.in/v2.1/events?filter=upcoming http://api.joind.in/v2.1/events/853 http://api.joind.in/v2.1/events/853/talks http://api.joind.in/v2.1/talks/6232
  21. Meaningful URLs 13 What would you expect to find at:

    http://api.joind.in/v2.1/events?filter=upcoming http://api.joind.in/v2.1/events/853 http://api.joind.in/v2.1/events/853/talks http://api.joind.in/v2.1/talks/6232 http://api.joind.in/v2.1/talks/6232/comments
  22. Verbs and URLs 14 These URLs give us representations of

    either resources or collections of resources We use HTTP verbs to operate on these resources Verb Collection Resource GET fetch resources fetch resource POST create a resource in this collection PUT create or update a resource here PATCH update part of a resource DELETE delete a resource
  23. Identifying Resources 15 What is a "resource"? • Maybe a

    database row • Maybe an item with some information from other tables • Talks also show speaker names, for example • Maybe a sub-resource
  24. Considering Sub-Resources 16 Common pitfall: http://example.com/articles/42/activate

  25. Considering Sub-Resources 16 Common pitfall: http://example.com/articles/42/activate We have two options

    GET http://example.com/articles/42, change the "active" flag, and PUT it back
  26. Considering Sub-Resources 16 Common pitfall: http://example.com/articles/42/activate We have two options

    GET http://example.com/articles/42, change the "active" flag, and PUT it back Make a subresource, then you can just work with http://example.com/articles/42/active
  27. Hypermedia

  28. Hypermedia 18 GET http://api.joind.in/v2.1/events/853

  29. Hypermedia 19 • Consumers can follow links rather than construct

    them • Providers can change link structures $event_url = 'http://api.joind.in/v2.1/events/853'; $event_data = json_decode( file_get_contents($event_url), TRUE); // get event talks $talks = json_decode( file_get_contents($event_data['events'][0]['talks_uri']), TRUE ); print_r($talks['talks'][0]);
  30. Content Negotiation

  31. Content Negotiation 21 We use the Accept and Content-Type headers

    to agree what formats to use. Common examples: • application/json • application/xml • text/html Next stage: use Media Types for custom/versioned representations
  32. Content Negotiation Confession 22 The joind.in API also allows ?format=json

    as an override
  33. Error Handling

  34. Simple Error Rules for Service Providers 24 • Use expected

    format • Give meaningful messages • Be consistent
  35. Exceptions Help Consistency 25 output controller model index

  36. Exceptions Help Consistency 26 function handle_exception($e) { // pull the

    correct format before we bail global $request; header("Status: " . $e->getCode(), false, $e->getCode()); $request->view->render(array($e->getMessage())); } set_exception_handler('handle_exception');
  37. When Things Go Wrong

  38. Crisis Strategies 28 • Lots of logging! • Logging rather

    than debug output if the client expects JSON • Proxy or network analyser • Inspects traffic without application changes • e.g. Wireshark or Charles proxy • Drop back to last known good outcome • Increase complexity in "baby steps"
  39. Protecting Yourself

  40. Isolate External Dependencies 30 Never call an API from your

    own code - have a class that wraps it. You can: • cache results if it is slow/flaky • replace it in one place later, if needed • write tests to check the API is still doing what you expect • write a mock object to replace it with for your own tests
  41. Respect the Danger 31 Website Digital Identity API Product API

    Database Mobile Application logic layer
  42. Respect the Danger 32 abyss Website Digital Identity API Product

    API Database Mobile Application logic layer
  43. Deliver on Time 33 How to estimate for API integration?

    • You can’t estimate an unknown task • Invest time in a prototype • In agile speak, a "spike"
  44. Best Practice for RESTful Applications 34 • Use existing tools,

    skills and conventions • Deliver what’s useful to your users • Plan defensively
  45. Questions?

  46. Thanks! 36 @lornajane http://lornajane.net