usable rest apis by javier ramirez at london ruby user group
DESCRIPTION
With the adoption of REST, the proliferation of smartphones and tablets, and the second coming of JavaScript, exposing our applications as a service is now more important than ever. Rails or Sinatra make really easy to create a (kinda) RESTful API but, in many occassions, these APIs are designed without really thinking on the developers that will have to use them. I want to talk about some of the points that can help making your API more developer-friendly. Some of the areas I’ll cover will be discoverability, authentication, headers, formats, parameters, documentation and tools. Talk delivered at London Ruby User Group on 12/12/2011TRANSCRIPT
![Page 1: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/1.jpg)
{"links":[ {"rel":"author", "uri":"http://javier-ramirez.com"}, {"rel":"work", "uri":"http://aspgems.com"}, {"rel":"blog", "uri":"http://formatinternet.com"}, {"rel":"twittEr", "uri":"http//twitter.com/supercoco9"}]}
usable REST APIs
![Page 2: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/2.jpg)
1996
![Page 3: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/3.jpg)
1995
![Page 4: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/4.jpg)
1996
![Page 5: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/5.jpg)
1994
![Page 6: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/6.jpg)
2001
![Page 7: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/7.jpg)
1999
![Page 8: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/8.jpg)
2004
![Page 9: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/9.jpg)
Web usability is an approach to make web sites
easy to use for an end-user, without the requirement that any specialized training be
undertaken.[]
![Page 10: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/10.jpg)
LearnabilityEfficIeNcyMemorabiliTyErrorsSatisfActiOn
![Page 11: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/11.jpg)
I want YOUto make
a (REST) API
![Page 12: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/12.jpg)
REST in a nutshell
client server stateless layered and cacheable
Resources
Resource Identifiers
Resource metadata
Uniform interface
operations
Representations
Representation metadata
Optionally: code on demand
![Page 13: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/13.jpg)
easy
making a REST API
with Rails?
![Page 14: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/14.jpg)
BASIC
WEB/api
functionality
IN RAILS
![Page 15: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/15.jpg)
Cohesion
pleasE
![Page 16: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/16.jpg)
separation of concerns
![Page 17: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/17.jpg)
SUCCESS consistently
fail consistently
![Page 18: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/18.jpg)
expose ONLY
WHAT ISStrictly
necessary
![Page 19: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/19.jpg)
resources are not models
![Page 20: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/20.jpg)
Aggregation/
composition
Multiple
representations
![Page 21: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/21.jpg)
Multiple consumers
![Page 22: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/22.jpg)
All your
FORMAT
are belong
to us
![Page 23: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/23.jpg)
> curl -d "[email protected]&password=keepdreaming" https://invoicefu.com/api/session?format=json
{"user":{"id":108,"name":"Nicolas Carroll","email":"[email protected]","locale":"en","twitter_nickname":null,"facebook_uid":null,"facebook_nickname":null,"api_key":"dbd349b30b6d9fde97b01b827e6be5ed1e4fbe72","links":[{"rel":"session","uri":"https://invoicefu.com/api/session","methods":"GET,POST,DESTROY"},"rel":"account","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake","methods":"GET,PUT"},"rel":"clients","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake/clients","methods":"GET,POST"},{"rel":"new_client","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake/clients/new","methods":"GET"},{"rel":"invoices","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake/invoices","methods":"GET,POST"},{"rel":"new_invoice","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake/invoices/new","methods":"GET"},{"rel":"proformas","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake/proformas","methods":"GET,POST"},{"rel":"new_proforma","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake/proformas/new","methods":"GET"}]}}
![Page 24: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/24.jpg)
> curl -d "[email protected]&password=yeahyeah" "https://invoicefu.com/api/session?&format=xml
<?xml version="1.0" encoding="UTF-8"?><user> <id>108</id> <name>Nicolas Carroll</name> <email>[email protected]</email> <locale>en</locale> <twitter-nickname nil="true"></twitter-nickname> <facebook-uid nil="true"></facebook-uid> <facebook-nickname nil="true"></facebook-nickname> <api-key>dbd349b30b6d9fde97b01b827e6be5ed1e4fbe72</api-key> <links> <link> <rel>session</rel> <uri>https://invoicefu-localhost.com/api/session</uri> <methods>GET,POST,DESTROY</methods> </link> <link> <rel>account</rel> <uri>https://invoicefu-localhost.com/api/accounts/108-cole-mertz-fake</uri> <methods>GET,PUT</methods> </link> <link> <rel>clients</rel> <uri>https://invoicefu-localhost.com/api/accounts/108-cole-mertz-fake/clients</uri> <methods>GET,POST</methods> </link> <link> <rel>new_client</rel> <uri>https://invoicefu-localhost.com/api/accounts/108-cole-mertz-fake/clients/new</uri> <methods>GET</methods> </link> (…)
</links></user>
can I haz cat readable anzwa
![Page 25: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/25.jpg)
THE
ACCEPT
HEADER
HTTP/REST StandardUnambiguousResources != RepresentationsVersion as you need it
Not everyone supports headers or custom types
Less obviousHarder to useNon standard content-typesSkips HTTP server logs
Accept: application/vnd.aspgems.invoicefu.v1.xml
![Page 26: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/26.jpg)
![Page 27: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/27.jpg)
![Page 28: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/28.jpg)
templates
for new
resources> curl "https://invoicefu.com/api/v1/accounts/108-cole-mertz-fake/invoices/new?api_key=ddd349b30b6d9fde97b01b827e6be5ed1e4fbe72&format=json"
{"invoice":{"number":"2011/30","issued_on":"2011-12-12","proforma_id":null,"notes":null,"footer":null,"locale":"en","currency_code":"USD","currency_symbol":"$","ac_name":"Cole-Mertz#FAKE","ac_company_number_name":"Company number","ac_company_number":"25465828K","ac_tax_number_name":"VAT Number","ac_tax_number":"ES25464828k","ac_address":"234 brecknock road","ac_city":"london","ac_province":null,"ac_postal_code":"n18 5bq","ac_country_name":"United Kingdom","cl_email":null,"cl_name":null,"cl_company_number_name":null,"cl_company_number":null,"cl_tax_number_name":null,"cl_tax_number":null,"cl_address":null,"cl_city":null,"cl_province":null,"cl_postal_code":null,"cl_country_name":null,"invoice_lines":[],"discount_percent":null,"tax_lines":[{"name":"TVA","signed_percent":"19.6"}],"paid":"0.0","links":[{"rel":"payments","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake/invoices//payments","methods":"POST"},{"rel":"account","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake","methods":"GET,PUT"},{"rel":"client","uri":null,"methods":"GET,PUT,DELETE"},{"rel":"proforma","uri":null,"methods":"GET,PUT,DELETE"},{"rel":"pdf","uri":null,"methods":"GET"},{"rel":"invoices","uri":"https://invoicefu.com/api/accounts/108-cole-mertz-fake/invoices","methods":"GET,POST"}]}}j
![Page 29: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/29.jpg)
EASy
To
FIND
![Page 30: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/30.jpg)
> curl https://invoicefu.com?format=xml (or curl -H "Accept: application/xml" "https://invoicefu.com")
<?xml version="1.0" encoding="UTF-8"?><invoicefu> <links> <link> <rel>session</rel> <uri>https://invoicefu.com/api/session</uri> <methods>POST.DELETE</methods> </link> <link> <rel>countries</rel> <uri>https://invoicefu.com/api/countries</uri> <methods>GET</methods> </link> <link> <rel>api_v1</rel> <uri>https://invoicefu.com/api/session?api_version=1</uri> <methods>POST.DELETE</methods> </link> <link> <rel>xml_representation</rel> <uri>https://invoicefu.com/api/session?format=xml</uri> <methods>POST.DELETE</methods> </link> <link> <rel>json_representation</rel> <uri>https://invoicefu.com/api/session?format=json</uri> <methods>POST.DELETE</methods> </link> <link> <rel>strict_parameters</rel> <uri>https://invoicefu.com/api/session?strict=true</uri> <methods>POST.DELETE</methods> </link> </links></invoicefu>
![Page 31: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/31.jpg)
> curl -d "[email protected]&password=yeahyeah" "https://invoicefu.com/api/session?&format=xml
<?xml version="1.0" encoding="UTF-8"?><user> <id>108</id> <name>Nicolas Carroll</name> <email>[email protected]</email> <locale>en</locale> <twitter-nickname nil="true"></twitter-nickname> <facebook-uid nil="true"></facebook-uid> <facebook-nickname nil="true"></facebook-nickname> <api-key>dbd349b30b6d9fde97b01b827e6be5ed1e4fbe72</api-key> <links> <link> <rel>session</rel> <uri>https://invoicefu-localhost.com/api/session</uri> <methods>GET,POST,DESTROY</methods> </link> <link> <rel>account</rel> <uri>https://invoicefu-localhost.com/api/accounts/108-cole-mertz-fake</uri> <methods>GET,PUT</methods> </link> <link> <rel>clients</rel> <uri>https://invoicefu-localhost.com/api/accounts/108-cole-mertz-fake/clients</uri> <methods>GET,POST</methods> </link> <link> <rel>new_client</rel> <uri>https://invoicefu-localhost.com/api/accounts/108-cole-mertz-fake/clients/new</uri> <methods>GET</methods> </link> <link> <rel>invoices</rel> <uri>https://invoicefu-localhost.com/api/accounts/108-cole-mertz-fake/invoices</uri> <methods>GET,POST</methods> </link>
(…)
</links></user>
![Page 32: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/32.jpg)
BASIC ACCESS AUTHENTICATION
OAUTH
TOKEN
authenticate_or_request_with_http_basic do |login, password| User.find_by_login_and_password login, password endUser and password must be passed every time
Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join ) User.find_by_login_and_api_key( params[:login], params[:api_key] ) Client can send it as a parameter or as a header
Depends on third party libraries Requires initial registration of client and more integration
![Page 33: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/33.jpg)
Performance
![Page 34: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/34.jpg)
params &
debug
![Page 35: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/35.jpg)
> curl "https://invoicefu.com/api/accounts/108-cole-mertz-fake/invoices/new?api_key=ddd349b30b6d9fde97b01b827e6be5ed1e4fbe72&format=xml&debug=1"
<?xml version="1.0" encoding="UTF-8"?><errors> <error>extra params found: debug. Allowed params are: account_id,client_id,invoice_id,proforma_id</error></errors>
> curl "https://invoicefu.com/api/accounts/108-cole-mertz-fake/invoices/new?api_key=ddd349b30b6d9fde97b01b827e6be5ed1e4fbe72&format=xml&debug=1&strict=false"<?xml version="1.0" encoding="UTF-8"?><invoice> <number>2011/30</number> <issued-on>2011-12-11</issued-on> <proforma-id nil="true"></proforma-id> (...) <links> (...) <link> <rel>invoices</rel> <uri>https://invoicefu-localhost.com/api/accounts/108-cole-mertz-fake/invoices</uri> <methods>GET,POST</methods> </link> </links></invoice>
![Page 36: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/36.jpg)
![Page 37: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/37.jpg)
WADLjson schema
helping
your users
![Page 38: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/38.jpg)
{ "name":"Product", "properties":{ "id":{ "type":"number", "description":"Product identifier", "required":true }, "name":{ "description":"Name of the product", "type":"string", "required":true }, "price":{ "required":true, "type": "number", "minimum":0, "required":true }, "tags":{ "type":"array", "items":{ "type":"string" } } }, "links":[ { "rel":"full", "href":"{id}" }, { "rel":"comments", "href":"comments/?id={id}" } ] }
<?xml version="1.0"?> <application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://wadl.dev.java.net/2009/02 wadl.xsd" xmlns:tns="urn:yahoo:yn" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:yn="urn:yahoo:yn" xmlns:ya="urn:yahoo:api" xmlns="http://wadl.dev.java.net/2009/02"> <grammars> <include href="NewsSearchResponse.xsd"/> <include href="Error.xsd"/> </grammars> <resources base="http://api.search.yahoo.com/NewsSearchService/V1/"> <resource path="newsSearch"> <method name="GET" id="search"> <request> <param name="appid" type="xsd:string" style="query" required="true"/> 22 <param name="type" style="query" default="all"> <option value="all"/> <option value="any"/> <option value="phrase"/> </param> <param name="start" style="query" type="xsd:int" default="1"/> <param name="language" style="query" type="xsd:string"/> </request> <response status="200"> <representation mediaType="application/xml" element="yn:ResultSet"/> </response> <response status="400"> <representation mediaType="application/xml" element="ya:Error"/> </response> </method> </resource> </resources> </application>
![Page 39: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/39.jpg)
tools
curl
Hurl
Httparty
restclient
![Page 40: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/40.jpg)
apigee
![Page 41: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/41.jpg)
![Page 42: Usable Rest APIs by Javier Ramirez at London Ruby User Group](https://reader034.vdocuments.mx/reader034/viewer/2022052522/554f5a83b4c905b9508b536e/html5/thumbnails/42.jpg)