Usable Rest APIs by Javier Ramirez at London Ruby User Group
Upcoming SlideShare
Loading in...5
×
 

Usable Rest APIs by Javier Ramirez at London Ruby User Group

on

  • 2,862 views

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. ...

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/2011

Statistics

Views

Total Views
2,862
Views on SlideShare
2,763
Embed Views
99

Actions

Likes
6
Downloads
17
Comments
2

7 Embeds 99

http://paper.li 46
http://coderwall.com 27
http://a0.twimg.com 12
http://planeta.aspgems.com 10
http://www.freelancit.com 2
http://www.hanrss.com 1
http://www.linkedin.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Usable Rest APIs by Javier Ramirez at London Ruby User Group Usable Rest APIs by Javier Ramirez at London Ruby User Group Presentation Transcript

  • usable REST APIs{"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"}]}
  • 1996
  • 1995
  • 1996
  • 1994
  • 2001
  • 1999
  • 2004
  • Web usability is anapproach to make web sites easy to use for an end-user, without the requirement that any specialized training be undertaken.[
  • LearnabilityEfficIeNcyMemorabiliTyErrorsSatisfActiOn
  • I want YOU to makea (REST) API
  • REST in a nutshellclient server stateless layered and cacheableResources Resource Identifiers Resource metadataUniform interface operations Representations Representation metadataOptionally: code on demand
  • making a REST API with Rails? easy
  • BASIC WEB/apifunctionality IN RAILS
  • CohesionpleasE
  • separation of concerns
  • SUCCESS consistently fail consistently
  • expose ONLY WHAT IS Strictlynecessary
  • resources are not models
  • Aggregation/ composition Multiple representations
  • Multiple consumers
  • All your FORMATare belong to us
  • > curl -d "login=ficticious_user@invoicefu.com&password=keepdreaming" https://invoicefu.com/api/session?format=json{"user":{"id":108,"name":"Nicolas Carroll","email":"ficticioususer@invoicefu.com","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"}]}}
  • can I haz cat readable anzwa> curl -d "login=ficticioususer@invoicefu.com&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>user000007@invoicefu.com</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>
  • Accept: application/vnd.aspgems.invoicefu.v1.xml THE ACCEPT HEADERHTTP/REST Standard Not everyone Less obviousUnambiguous supports headers Harder to useResources != or custom types Non standard content-Representations typesVersion as you need it Skips HTTP server logs
  • 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":"Companynumber","ac_company_number":"25465828K","ac_tax_number_name":"VATNumber","ac_tax_number":"ES25464828k","ac_address":"234 brecknockroad","ac_city":"london","ac_province":null,"ac_postal_code":"n18 5bq","ac_country_name":"UnitedKingdom","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
  • EASy To FIND
  • > 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>
  • > curl -d "login=ficticioususer@invoicefu.com&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>user000007@invoicefu.com</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>
  • BASIC ACCESS AUTHENTICATION authenticate_or_request_with_http_basic do |login, password| User.find_by_login_and_password login, password endUser and password must be passed every timeTOKENDigest::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 headerOAUTHDepends on third party librariesRequires initial registration of client and more integration
  • Performance
  • params & debug
  • > 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>
  • helping your users WADLjson schema
  • { <?xml version="1.0"?> "name":"Product", <application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" "properties":{ xsi:schemaLocation="http://wadl.dev.java.net/2009/02 wadl.xsd" "id":{ xmlns:tns="urn:yahoo:yn" "type":"number", xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:yn="urn:yahoo:yn" "description":"Product identifier", xmlns:ya="urn:yahoo:api" "required":true xmlns="http://wadl.dev.java.net/2009/02"> }, <grammars> "name":{ <include "description":"Name of the href="NewsSearchResponse.xsd"/>product", <include "type":"string", href="Error.xsd"/> "required":true </grammars> }, "price":{ <resources base="http://api.search.yahoo.com/NewsSearchService/V1/"> <resource path="newsSearch"> "required":true, <method name="GET" id="search"> "type": "number", <request> "minimum":0, <param name="appid" type="xsd:string" "required":true style="query" required="true"/> 22 }, <param name="type" style="query" default="all"> "tags":{ <option value="all"/> "type":"array", <option value="any"/> "items":{ <option value="phrase"/> "type":"string" </param> } <param name="start" style="query" type="xsd:int" default="1"/> <param name="language" style="query" type="xsd:string"/> } </request> }, <response status="200"> "links":[ <representation mediaType="application/xml" { element="yn:ResultSet"/> "rel":"full", </response> "href":"{id}" <response status="400"> }, <representation mediaType="application/xml" { element="ya:Error"/> "rel":"comments", </response> "href":"comments/?id={id}" </method> </resource> } </resources> ] } </application>
  • toolscurlHurlHttpartyrestclient
  • apigee