Web Services Tutorial
Lorna Mitchell  • PHP Consultant/Developer/Trainer  • API Specialist  • Author and Speaker  • Open Source Project Lead (ht...
Agenda  • Web Services and a Simple Example  • HTTP and Data Formats  • Consuming Services from PHP  • Service Types and S...
Theory and Introduction
What Is A Web Service? • Means of exposing functionality or data • A lot like a web page • Integration between application...
Web Services and You             This is not rocket science      You already know most of what you need!                  ...
Architecture Using APIsCommon to use an API internally as well as exposing it                                             ...
Let’s Begin
Building BlocksYou can make an API from any tools you like  • Existing MVC setup  • Simple PHP (as in these examples)  • F...
My First Web Service  • Make a virtual host      • e.g. http://api.local      • Don’t forget to restart apache      • Add ...
My First Web Service  • Create the index.php file      • e.g. /var/www/myapi/public/index.php$data = array(    format => js...
Consume Your Service • curl http://api.local • For more information about curl:     • http://curl.haxx.se/     • http://bi...
JSON JavaScript Object Notation   • Originally for JavaScript   • Native read/write in most languages   • Simple, lightwei...
Heartbeat Method • A method which does nothing • No authentication • Requires correct request format • Gives basic feedbac...
Delivering A Web Service   • Service   • Documentation   • Examples   • A help pointIf you’re only going to build the serv...
HTTP and Data Formats
HTTPHTTP is Hypertext Transfer Protocol - we’ll recap on some key elements:  • Status Codes (e.g. 200, 404)  • Headers (e....
Status CodesA headline response. Common codes:                      200   OK                      302   Found             ...
Working with Status Codes in PHPWe can observe status codes with curl, passing the -I switchcurl -I http://api.localLet’s ...
HTTP Verbs  • More than GET and POST  • PUT and DELETE to update and delete in a RESTful service  • HEAD, OPTIONS and othe...
HTTP HeadersHeaders are the metadata about the content we send/receiveUseful headers:  • Accept and Content-Type: used for...
Accept HeaderWhat type of content can the consumer understand?    • -v with curl to see request and response headers    • ...
Using the Accept HeaderWe can work out what format the user wanted to see from the Acceptheader.$data = array(    status =...
Content-Type HeaderThe Content-Type header: literally labels the contents of the response.We can include these in our exam...
Handling XML FormatsWe can work with XML in PHP almost as easily  • Content type is text/xml or application/xml  • Two XML...
Adding XML to Our Service$data = array(    status => live,    now => time()    );$simplexml = simplexml_load_string(<?xml ...
How to REALLY Handle Accept HeadersExample accept header (from my browser)text/html, application/xml;q=0.9, application/xh...
Versions and Formats • Always include a version parameter or media type • Handle multiple formats, by header or parameter ...
Statelessness • Request alone contains all information needed • No data persistence between requests • Resource does not n...
Consuming Services from PHP
Consuming Your First Web ServiceThree ways to consume web services:  • Via streams (e.g. file_get_contents and some context...
Using File_Get_ContentsThis is the simplest, useful for GET requests$response = file_get_contents(http://api.local/);var_d...
Using CurlThis extension is commonly available$ch = curl_init(http://api.local/);curl_setopt($ch, CURLOPT_RETURNTRANSFER, ...
Using Pecl_HTTPThis is the most powerful and flexible, and can easily be installed fromhttp://pecl.php.net$request = new HT...
Service Types
Web Service TypesThere are a few types of web service  • RESTful  • RPC (Remote Procedure Call)       • XML-RPC       • JS...
RPC ServicesThese services typically have:   • A single endpoint   • Method names   • Method parameters   • A return value...
Soap • Not an acronym       • (used to stand for Simple Object Access Protocol) • Special case of XML-RPC • VERY easy to d...
Soap Example: Library Classclass Library {    public function thinkOfANumber() {        return 42;    }    public function...
Publishing a Soap Service(don’t blink or you will miss it!)include(Library.php);$options = array(uri => http://api.local/s...
Consuming a Soap ServiceTo call PHP directly, we would do:include(Library.php);$lib = new Library();$name = $lib->thinkOfA...
Pros and Cons of Soap • Many languages have libraries for it • .NET and Java programmers in particular like it            ...
Pros and Cons of Soap • Many languages have libraries for it • .NET and Java programmers in particular like it • Weird thi...
Pros and Cons of Soap • Many languages have libraries for it • .NET and Java programmers in particular like it • Weird thi...
Pros and Cons of Soap • Many languages have libraries for it • .NET and Java programmers in particular like it • Weird thi...
Working with WSDLsWSDL stands for Web Service Description Language  • WSDLs were not designed for humans to read  • They a...
Debugging SoapThe Soap extension has some debug methods:   • Set the options to include trace=1 in the SoapClient   • getL...
Wireshark Demo  Bear with me while I fire up wireshark to show you                                                      45
Extending Our Service
Consistency • Important to retain     • Naming conventions     • Parameter validation rules     • Parameter order • Just a...
The Action ParameterAs a simple place to start, let’s add an action parameter.// route the request (filter input!)$action ...
Small APIs • Beware adding new functionality • Simple is maintainable • Easy to use and understand                        ...
Adding an ActionTo add a new action, create a new method for the Actions class, returningan array to pass to the output ha...
Access ControlA few common ways to identify users  • Username and password with every request  • Login action and give a t...
RPC Service Example: FlickrTake a look at http://www.flickr.com/services/api/   • Supports multiple formats (for request a...
RPC vs RESTWe’ve seen an RPC service, but what about REST? The two are quitedifferent  • RPC services describe protocols, ...
RESTful Web Service
REST  • REpresentational State Transfer  • URLs are unique resource identifiers  • HTTP verbs indicate which operation shou...
REST as a ReligionBeware publishing a service labelled "RESTful"  • Someone will always tell you it isn’t  • They are prob...
Making Our Service RestfulWe’re aiming for URLs that look something like this:   • http://api.local/rest/user   • http://a...
All Requests to index.phpWe want to push all requests through index.php, there is an .htaccess filethat does this<IfModule ...
Routing Within Our AppSo our routing depends on the URL and on the verb used, so ourcontrollers have a method per verb:  •...
A Simple ControllerNow in UserController we add a GETActionclass UsersController {    public function GETAction($parameter...
Calling our ServiceExample uses curl, there are options$ch = curl_init(http://api.local/rest/users);curl_setopt($ch, CURLO...
Extending our ServiceNext we will add something to get the user’s friendshttp://api.local/users/1/friendsclass UsersContro...
Hypermedia • The items returned are resources with their URLs • This is hypermedia - providing links to related items/coll...
Creating New RecordsRESTful services use POST for creating data, so we have POSTAction    public function POSTAction($path...
Incoming POST/PUT DataWe read from php://input which is a stream. So for JSON:$verb = $_SERVER[REQUEST_METHOD];$data = arr...
POSTing JSON Data from PHPAdding some appropriate data handling and headers to the curl call:$data = array("name" => "Hagr...
Appropriate Status Codes for REST • GET    • 200 or maybe 302 if we found it somewhere else    • 404 if we can’t find it • ...
Responding to Failure  • Use expected response format  • Collate all errors and return  • Help users help themselves  • Be...
Delivering Services
Technical AspectsAll PHP Best Practices apply equally to APIs   • Source control   • Unit/Integration testing   • Automate...
User AspectsWho will use your API?  • Offer API Docs  • Write a quick start for the impatient  • Show examples, as many as...
Questions?
ResourcesAll links are in the bit.ly bundle bit.ly/emRpYT                                                   73
Thanks • http://joind.in/talk/view/3461 • http://lornajane.net                                    74
Upcoming SlideShare
Loading in …5
×

Web services tutorial

14,901
-1

Published on

Slides for the tutorial I gave at PHPNW11 covering all aspects of working with web services from PHP

Published in: Technology

Web services tutorial

  1. 1. Web Services Tutorial
  2. 2. Lorna Mitchell • PHP Consultant/Developer/Trainer • API Specialist • Author and Speaker • Open Source Project Lead (http://joind.in) • Twitter: @lornajane • Site: http://lornajane.net 2
  3. 3. Agenda • Web Services and a Simple Example • HTTP and Data Formats • Consuming Services from PHP • Service Types and Soap • RPC Services • Building RESTful servicesCode samples at: http://bit.ly/fE0f6f 3
  4. 4. Theory and Introduction
  5. 5. What Is A Web Service? • Means of exposing functionality or data • A lot like a web page • Integration between applications • Separation within an application 5
  6. 6. Web Services and You This is not rocket science You already know most of what you need! 6
  7. 7. Architecture Using APIsCommon to use an API internally as well as exposing it 7
  8. 8. Let’s Begin
  9. 9. Building BlocksYou can make an API from any tools you like • Existing MVC setup • Simple PHP (as in these examples) • Framework module • Component library 9
  10. 10. My First Web Service • Make a virtual host • e.g. http://api.local • Don’t forget to restart apache • Add an entry to your hosts file<VirtualHost *:80> ServerName api.local ServerAdmin admin@localhost DocumentRoot /var/www/myapi/public <Directory /var/www/myapi/public> AllowOverride All Order deny,allow Allow from All </Directory></VirtualHost> api.vhost 10
  11. 11. My First Web Service • Create the index.php file • e.g. /var/www/myapi/public/index.php$data = array( format => json, status => live );echo json_encode($data); public/index.php 11
  12. 12. Consume Your Service • curl http://api.local • For more information about curl: • http://curl.haxx.se/ • http://bit.ly/esqBmz 12
  13. 13. JSON JavaScript Object Notation • Originally for JavaScript • Native read/write in most languages • Simple, lightweight format - useful for mobile • In PHP we have json_encode and json_decode • These work with arrays and objectsOur service returns:{format:json,status:live} 13
  14. 14. Heartbeat Method • A method which does nothing • No authentication • Requires correct request format • Gives basic feedback • Shows that service is alive 14
  15. 15. Delivering A Web Service • Service • Documentation • Examples • A help pointIf you’re only going to build the service, don’t bother 15
  16. 16. HTTP and Data Formats
  17. 17. HTTPHTTP is Hypertext Transfer Protocol - we’ll recap on some key elements: • Status Codes (e.g. 200, 404) • Headers (e.g. Content-Type, Authorization) • Verbs (e.g GET, POST) 17
  18. 18. Status CodesA headline response. Common codes: 200 OK 302 Found 301 Moved 401 Not Authorised 403 Forbidden 404 Not Found 500 Internal Server ErrorConsumers can get a WIN/FAIL indicator before unpacking the responsein full 18
  19. 19. Working with Status Codes in PHPWe can observe status codes with curl, passing the -I switchcurl -I http://api.localLet’s amend our web service, to return a 302 headerheader("302 Found", true, 302);$data = array( format => json, status => live );echo json_encode($data); 19
  20. 20. HTTP Verbs • More than GET and POST • PUT and DELETE to update and delete in a RESTful service • HEAD, OPTIONS and others also specified GET Read POST CreateIn REST, we use: PUT Update DELETE Delete 20
  21. 21. HTTP HeadersHeaders are the metadata about the content we send/receiveUseful headers: • Accept and Content-Type: used for content format negotiation • User-Agent: to identify what made the request • Set-Cookie and Cookie: working with cookie data • Authorization: controlling access 21
  22. 22. Accept HeaderWhat type of content can the consumer understand? • -v with curl to see request and response headers • -H to add headerscurl -v -H "Accept: text/html" http://api.localGives the output:* About to connect() to api.local port 80 (#0)* Trying 127.0.0.1... connected* Connected to api.local (127.0.0.1) port 80 (#0)> GET / HTTP/1.1> User-Agent: curl/7.21.0 (i686-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0> Host: api.local> Accept: text/html> 22
  23. 23. Using the Accept HeaderWe can work out what format the user wanted to see from the Acceptheader.$data = array( status => live, now => time() );if(false !== strpos($_SERVER[HTTP_ACCEPT], text/html)) { echo "<pre>"; print_r($data); echo "</pre>";} else { // return json echo json_encode($data);} public/headers.php 23
  24. 24. Content-Type HeaderThe Content-Type header: literally labels the contents of the response.We can include these in our examples:$data = array( status => live, now => time() );if(false !== strpos($_SERVER[HTTP_ACCEPT], text/html)) { header(Content-Type: text/html); echo "<pre>"; print_r($data); echo "</pre>";} else { // return json header(Content-Type: application/json); echo json_encode($data);} public/headers.php 24
  25. 25. Handling XML FormatsWe can work with XML in PHP almost as easily • Content type is text/xml or application/xml • Two XML libraries in PHP • SimpleXML bit.ly/g1xpaP • DOM bit.ly/e0XMzd • Give consumers a choice of formats 25
  26. 26. Adding XML to Our Service$data = array( status => live, now => time() );$simplexml = simplexml_load_string(<?xml version="1.0" ?><data />);foreach($data as $key => $value) { $simplexml->addChild($key, $value);}header(Content-Type: text/xml);echo $simplexml->asXML();The result is this:<?xml version="1.0"?><data><status>live</status><now>1302981884</now></data> 26
  27. 27. How to REALLY Handle Accept HeadersExample accept header (from my browser)text/html, application/xml;q=0.9, application/xhtml+xml,image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1 • See a much nicer example of this in headers-accept.php • Taken almost entirely from the source of arbitracker • http://arbitracker.org • src/classes/request/parser.php • Try this from curl, setting your own headers, and from your browser 27
  28. 28. Versions and Formats • Always include a version parameter or media type • Handle multiple formats, by header or parameter • JSON • XML • HTML • ? • Common to detect header, allow parameter override 28
  29. 29. Statelessness • Request alone contains all information needed • No data persistence between requests • Resource does not need to be in known state • Same operation performs same outcome 29
  30. 30. Consuming Services from PHP
  31. 31. Consuming Your First Web ServiceThree ways to consume web services: • Via streams (e.g. file_get_contents and some context) • Using the curl extension • bit.ly/h5dhyT • Using Pecl_HTTP • bit.ly/g4CfPw 31
  32. 32. Using File_Get_ContentsThis is the simplest, useful for GET requests$response = file_get_contents(http://api.local/);var_dump($response);You can set more information in the stream context bit.ly/gxBAgV 32
  33. 33. Using CurlThis extension is commonly available$ch = curl_init(http://api.local/);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);$response = curl_exec($ch);var_dump($response);Look out for the CURLOPT_RETURNTRANSFER; without it, this will echothe output 33
  34. 34. Using Pecl_HTTPThis is the most powerful and flexible, and can easily be installed fromhttp://pecl.php.net$request = new HTTPRequest(http://api.local/, HTTP_METH_GET);$request->send();$response = $request->getResponseBody();var_dump($response);Strongly recommend pecl_http if you are able to install pecl modules onyour platform 34
  35. 35. Service Types
  36. 36. Web Service TypesThere are a few types of web service • RESTful • RPC (Remote Procedure Call) • XML-RPC • JSON-RPC • Soap 36
  37. 37. RPC ServicesThese services typically have: • A single endpoint • Method names • Method parameters • A return valueA familiar model for us as developers 37
  38. 38. Soap • Not an acronym • (used to stand for Simple Object Access Protocol) • Special case of XML-RPC • VERY easy to do in PHP • Can be used with a WSDL • Web Service Description Language 38
  39. 39. Soap Example: Library Classclass Library { public function thinkOfANumber() { return 42; } public function thinkOfAName() { return Arthur Dent; }} /public/soap/Library.php 39
  40. 40. Publishing a Soap Service(don’t blink or you will miss it!)include(Library.php);$options = array(uri => http://api.local/soap);$server = new SoapServer(NULL, $options);$server->setClass(Library);$server->handle(); /public/soap/index.php 40
  41. 41. Consuming a Soap ServiceTo call PHP directly, we would do:include(Library.php);$lib = new Library();$name = $lib->thinkOfAName();echo $name; // Arthur DentOver Soap:$options = array(uri => http://api.local, location => http://api.local/soap);$client = new SoapClient(NULL, $options);$name = $client->thinkOfAName();echo $name; // Arthur Dent 41
  42. 42. Pros and Cons of Soap • Many languages have libraries for it • .NET and Java programmers in particular like it 42
  43. 43. Pros and Cons of Soap • Many languages have libraries for it • .NET and Java programmers in particular like it • Weird things happen between languages regarding data types 42
  44. 44. Pros and Cons of Soap • Many languages have libraries for it • .NET and Java programmers in particular like it • Weird things happen between languages regarding data types • When it works, it’s marvellous • When it doesn’t work, it’s horrid to debug (so I’ll show you how) 42
  45. 45. Pros and Cons of Soap • Many languages have libraries for it • .NET and Java programmers in particular like it • Weird things happen between languages regarding data types • When it works, it’s marvellous • When it doesn’t work, it’s horrid to debug (so I’ll show you how) • WSDL is complicated! 42
  46. 46. Working with WSDLsWSDL stands for Web Service Description Language • WSDLs were not designed for humans to read • They are written in XML, and are very verbose • If you do need to read one, start at the END and read upwards in sections • Soap uses very strict data typing, which is an unknown concept in PHPRead about WSDLs: bit.ly/eNZOmp 43
  47. 47. Debugging SoapThe Soap extension has some debug methods: • Set the options to include trace=1 in the SoapClient • getLastRequest(), getLastRequestHeaders(), getLastResponse(), getLastResponseHeaders() are then availableFor all web service types, you can use: • I like Wireshark (http://www.wireshark.org) • Others use Charles (http://www.charlesproxy.com) • If you like reading XML then use curl • SoapUI (http://soapui.org) 44
  48. 48. Wireshark Demo Bear with me while I fire up wireshark to show you 45
  49. 49. Extending Our Service
  50. 50. Consistency • Important to retain • Naming conventions • Parameter validation rules • Parameter order • Just as you would in library code 47
  51. 51. The Action ParameterAs a simple place to start, let’s add an action parameter.// route the request (filter input!)$action = $_GET[action];$library = new Actions();$data = $library->$action(); /rpc/index.phpHere’s the code for the Actions classclass Actions { public function getSiteStatus() { return array(status => healthy, time => date(d-M-Y)); }} /rpc/actions.phpSo try http://api.local/rpc/index.php?action=getSiteStatus 48
  52. 52. Small APIs • Beware adding new functionality • Simple is maintainable • Easy to use and understand 49
  53. 53. Adding an ActionTo add a new action, create a new method for the Actions class, returningan array to pass to the output handlers public function addTwoNumbers($params) { return array(result => ($params[a] + $params[b])); } /rpc/actions.phpBut how do we pass the parameters in? Something like this// route the request (filter input!)$action = $_GET[action];$library = new Actions();// OBVIOUSLY you would filter input at this point$data = $library->$action($_GET); /rpc/index.php 50
  54. 54. Access ControlA few common ways to identify users • Username and password with every request • Login action and give a token to use • OAuth • For internal applications, firewalls 51
  55. 55. RPC Service Example: FlickrTake a look at http://www.flickr.com/services/api/ • Supports multiple formats (for request and response) • Is well-documented and consistent • Has libraries helping users to consume it • Offers both RPC and RESTful (kind of!) interfaces • Follows true XML-RPC (see http://en.wikipedia.org/wiki/Xml-rpc)Vast numbers of applications using this API to provide flickr functionalityelsewhere 52
  56. 56. RPC vs RESTWe’ve seen an RPC service, but what about REST? The two are quitedifferent • RPC services describe protocols, e.g. XML-RPC • RPC is a familiar: functions and arguments • REST is a set of principles • Takes advantage of HTTP features • Typically has "pretty URLs", e.g. Twitter is mostly RESTful 53
  57. 57. RESTful Web Service
  58. 58. REST • REpresentational State Transfer • URLs are unique resource identifiers • HTTP verbs indicate which operation should happen • We have full CRUD operations on a series of resourcesHere’s one I prepared earlier: /public/rest/ 55
  59. 59. REST as a ReligionBeware publishing a service labelled "RESTful" • Someone will always tell you it isn’t • They are probably right • The strict rules around REST sometimes fit badly around business requirements • Flamewars will ensueInstead: "An HTTP Web Service" 56
  60. 60. Making Our Service RestfulWe’re aiming for URLs that look something like this: • http://api.local/rest/user • http://api.local/rest/user/3 • http://api.local/rest/user/3/friendsA specific item is a resource; where you request a list, e.g. /user, this iscalled a collection 57
  61. 61. All Requests to index.phpWe want to push all requests through index.php, there is an .htaccess filethat does this<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1 [L]</IfModule> /public/rest/.htaccess 58
  62. 62. Routing Within Our AppSo our routing depends on the URL and on the verb used, so ourcontrollers have a method per verb: • GET /user • Becomes UserController::GETAction()// route the request (filter input!)$verb = $_SERVER[REQUEST_METHOD];$action_name = strtoupper($verb) . Action;$url_params = explode(/,$_SERVER[PATH_INFO]);$controller_name = ucfirst($url_params[1]) . Controller;$controller = new $controller_name();$data = $controller->$action_name($url_params);// output appropriately$view->render($data); /public/rest/index.php 59
  63. 63. A Simple ControllerNow in UserController we add a GETActionclass UsersController { public function GETAction($parameters) { $users = array(); // imagine retreving data from models if(isset($parameters[2])) { return $users[(int)$parameters[2]]; } else { return $users; } }} /public/rest/controllers.php 60
  64. 64. Calling our ServiceExample uses curl, there are options$ch = curl_init(http://api.local/rest/users);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);$result = curl_exec($ch);print_r(json_decode($result, true)); /public/rest-test.php 61
  65. 65. Extending our ServiceNext we will add something to get the user’s friendshttp://api.local/users/1/friendsclass UsersController { public function GETAction($parameters) { $users = array(); $friends = array(); // imagine retreving data from models if(isset($parameters[2])) { if(isset($parameters[3]) && $parameters[3] == friends) { return $friends[(int)$parameters[2]]; } else { return $users[(int)$parameters[2]]; } } else { return $users; } }} /public/rest/controllers.php 62
  66. 66. Hypermedia • The items returned are resources with their URLs • This is hypermedia - providing links to related items/collections • Allows a service to be self-documenting • Allows a service to change its URLs - because they’re provided 63
  67. 67. Creating New RecordsRESTful services use POST for creating data, so we have POSTAction public function POSTAction($path, $data) { // sanitise and validate data please! // create a user from params $new_user[name] = isset($data[name]) ? $data[name] : ; $new_user[house] = isset($data[house]) ? $data[house] : $new_user[age] = isset($data[age]) ? $data[age] : ; // save the user, return the new id $new_user[self] = http:// . $_SERVER[HTTP_HOST] . /rest // redirect user header(HTTP/1.1 201 Created); header(Location: http://api.local/rest/users/5); return $new_user; } /public/rest/controllers.php 64
  68. 68. Incoming POST/PUT DataWe read from php://input which is a stream. So for JSON:$verb = $_SERVER[REQUEST_METHOD];$data = array();switch($verb) { case GET: parse_str($_SERVER[QUERY_STRING], $data); break; case POST: case PUT: // incoming JSON data, its an array $data = json_decode(file_get_contents(php://input), true); break; /public/rest/index.php 65
  69. 69. POSTing JSON Data from PHPAdding some appropriate data handling and headers to the curl call:$data = array("name" => "Hagrid", "age" => "36");$data_string = json_encode($data);$ch = curl_init(http://api.local/rest/users);curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HTTPHEADER, array( Content-Type: application/json, Content-Length: . strlen($data_string)));$result = curl_exec($ch);print_r(json_decode($result, true)); /public/rest-test.php 66
  70. 70. Appropriate Status Codes for REST • GET • 200 or maybe 302 if we found it somewhere else • 404 if we can’t find it • POST • 201 and a location header to the new resource • or 400 if we can’t create an item • PUT • 204 for OK (but no content) • 400 if the supplied data was invalid • DELETE • 200 at all times, for idempotency 67
  71. 71. Responding to Failure • Use expected response format • Collate all errors and return • Help users help themselves • Be consistent • Be accurate 68
  72. 72. Delivering Services
  73. 73. Technical AspectsAll PHP Best Practices apply equally to APIs • Source control • Unit/Integration testing • Automated deployment • MonitoringReliability and consistency are key 70
  74. 74. User AspectsWho will use your API? • Offer API Docs • Write a quick start for the impatient • Show examples, as many as possible • Tutorials, blog posts, links to forum answers, anything • Respond to questions 71
  75. 75. Questions?
  76. 76. ResourcesAll links are in the bit.ly bundle bit.ly/emRpYT 73
  77. 77. Thanks • http://joind.in/talk/view/3461 • http://lornajane.net 74
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×