web services tutorial

77
Web Services Tutorial

Upload: lorna-mitchell

Post on 19-May-2015

13.041 views

Category:

Technology


0 download

DESCRIPTION

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

TRANSCRIPT

Page 1: Web services tutorial

Web Services Tutorial

Page 2: Web services tutorial

Lorna Mitchell

2

• PHP Consultant/Developer/Trainer

• API Specialist

• Author and Speaker

• Open Source Project Lead (http://joind.in)

• Twitter: @lornajane

• Site: http://lornajane.net

Page 3: Web services tutorial

Agenda

3

• Web Services and a Simple Example

• HTTP and Data Formats

• Consuming Services from PHP

• Service Types and Soap

• RPC Services

• Building RESTful services

Code samples at: http://bit.ly/fE0f6f

Page 4: Web services tutorial

Theory and Introduction

Page 5: Web services tutorial

What Is A Web Service?

5

• Means of exposing functionality or data

• A lot like a web page

• Integration between applications

• Separation within an application

Page 6: Web services tutorial

Web Services and You

6

This is not rocket science

You already know most of what you need!

Page 7: Web services tutorial

Architecture Using APIs

7

Common to use an API internally as well as exposing it

Page 8: Web services tutorial

Let’s Begin

Page 9: Web services tutorial

Building Blocks

9

You can make an API from any tools you like

• Existing MVC setup

• Simple PHP (as in these examples)

• Framework module

• Component library

Page 10: Web services tutorial

My First Web Service

10

• 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.localServerAdmin admin@localhostDocumentRoot /var/www/myapi/public

<Directory /var/www/myapi/public>AllowOverride AllOrder deny,allowAllow from All

</Directory></VirtualHost>

api.vhost

Page 11: Web services tutorial

My First Web Service

11

• 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

Page 12: Web services tutorial

Consume Your Service

12

• curl http://api.local

• For more information about curl:

• http://curl.haxx.se/

• http://bit.ly/esqBmz

Page 13: Web services tutorial

JSON JavaScript Object Notation

13

• 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 objects

Our service returns:

{'format':'json','status':'live'}

Page 14: Web services tutorial

Heartbeat Method

14

• A method which does nothing

• No authentication

• Requires correct request format

• Gives basic feedback

• Shows that service is alive

Page 15: Web services tutorial

Delivering A Web Service

15

• Service

• Documentation

• Examples

• A help point

If you’re only going to build the service, don’t bother

Page 16: Web services tutorial

HTTP and Data Formats

Page 17: Web services tutorial

HTTP

17

HTTP 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)

Page 18: Web services tutorial

Status Codes

18

A headline response. Common codes:

200 OK

302 Found

301 Moved

401 Not Authorised

403 Forbidden

404 Not Found

500 Internal Server Error

Consumers can get a WIN/FAIL indicator before unpacking the responsein full

Page 19: Web services tutorial

Working with Status Codes in PHP

19

We can observe status codes with curl, passing the -I switch

curl -I http://api.local

Let’s amend our web service, to return a 302 header

header ( "302 Found" , true , 302);

$data = array ('format' => 'json' ,'status' => 'live');

echo json_encode ($data);

Page 20: Web services tutorial

HTTP Verbs

20

• More than GET and POST

• PUT and DELETE to update and delete in a RESTful service

• HEAD, OPTIONS and others also specified

In REST, we use:

GET Read

POST Create

PUT Update

DELETE Delete

Page 21: Web services tutorial

HTTP Headers

21

Headers are the metadata about the content we send/receive

Useful 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

Page 22: Web services tutorial

Accept Header

22

What type of content can the consumer understand?

• -v with curl to see request and response headers

• -H to add headers

curl -v -H "Accept: text/html" http://api.local

Gives 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.9.8> Host: api.local> Accept: text/html>

Page 23: Web services tutorial

Using the Accept Header

23

We 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 jsonecho json_encode ($data);

}

public/headers.php

Page 24: Web services tutorial

Content-Type Header

24

The 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 jsonheader ( 'Content-Type: application/json' );echo json_encode ($data);

}

public/headers.php

Page 25: Web services tutorial

Handling XML Formats

25

We 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

Page 26: Web services tutorial

Adding XML to Our Service

26

$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></d ata>

Page 27: Web services tutorial

How to REALLY Handle Accept Headers

27

Example accept header (from my browser)

text/html, application/xml;q=0.9, application/xhtml+x ml,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

Page 28: Web services tutorial

Versions and Formats

28

• 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

Page 29: Web services tutorial

Statelessness

29

• 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

Page 30: Web services tutorial

Consuming Services from PHP

Page 31: Web services tutorial

Consuming Your First Web Service

31

Three 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

Page 32: Web services tutorial

Using File_Get_Contents

32

This 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

Page 33: Web services tutorial

Using Curl

33

This 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

Page 34: Web services tutorial

Using Pecl_HTTP

34

This 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

Page 35: Web services tutorial

Service Types

Page 36: Web services tutorial

Web Service Types

36

There are a few types of web service

• RESTful

• RPC (Remote Procedure Call)

• XML-RPC

• JSON-RPC

• Soap

Page 37: Web services tutorial

RPC Services

37

These services typically have:

• A single endpoint

• Method names

• Method parameters

• A return value

A familiar model for us as developers

Page 38: Web services tutorial

Soap

38

• 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

Page 39: Web services tutorial

Soap Example: Library Class

39

class Library {public function thinkOfANumber() {

return 42;}

public function thinkOfAName() {return 'Arthur Dent' ;

}}

/public/soap/Library.php

Page 40: Web services tutorial

Publishing a Soap Service

40

(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

Page 41: Web services tutorial

Consuming a Soap Service

41

To call PHP directly, we would do:

include ( 'Library.php' );

$lib = new Library();$name = $lib->thinkOfAName();echo $name; // Arthur Dent

Over Soap:

$options = array ( 'uri' => 'http://api.local' ,'location' => 'http://api.local/soap' );

$client = new SoapClient( NULL, $options);

$name = $client->thinkOfAName();echo $name; // Arthur Dent

Page 42: Web services tutorial

Pros and Cons of Soap

42

• Many languages have libraries for it

• .NET and Java programmers in particular like it

Page 43: Web services tutorial

Pros and Cons of Soap

42

• Many languages have libraries for it

• .NET and Java programmers in particular like it

• Weird things happen between languages regarding data types

Page 44: Web services tutorial

Pros and Cons of Soap

42

• 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)

Page 45: Web services tutorial

Pros and Cons of Soap

42

• 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!

Page 46: Web services tutorial

Working with WSDLs

43

WSDL 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 insections

• Soap uses very strict data typing, which is an unknown concept inPHP

Read about WSDLs: bit.ly/eNZOmp

Page 47: Web services tutorial

Debugging Soap

44

The Soap extension has some debug methods:

• Set the options to include trace=1 in the SoapClient

• getLastRequest() , getLastRequestHeaders() ,getLastResponse() , getLastResponseHeaders() are thenavailable

For 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)

Page 48: Web services tutorial

Wireshark Demo

45

Bear with me while I fire up wireshark to show you

Page 49: Web services tutorial

Extending Our Service

Page 50: Web services tutorial

Consistency

47

• Important to retain

• Naming conventions

• Parameter validation rules

• Parameter order

• Just as you would in library code

Page 51: Web services tutorial

The Action Parameter

48

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

Here’s the code for the Actions class

class Actions {public function getSiteStatus() {

return array ( 'status' => 'healthy' ,'time' => date ( 'd-M-Y' ));

}}

/rpc/actions.php

So try http://api.local/rpc/index.php?action=getSiteStatus

Page 52: Web services tutorial

Small APIs

49

• Beware adding new functionality

• Simple is maintainable

• Easy to use and understand

Page 53: Web services tutorial

Adding an Action

50

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

But 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

Page 54: Web services tutorial

Access Control

51

A 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

Page 55: Web services tutorial

RPC Service Example: Flickr

52

Take 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 (seehttp://en.wikipedia.org/wiki/Xml-rpc)

Vast numbers of applications using this API to provide flickr functionalityelsewhere

Page 56: Web services tutorial

RPC vs REST

53

We’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

Page 57: Web services tutorial

RESTful Web Service

Page 58: Web services tutorial

REST

55

• REpresentational State Transfer

• URLs are unique resource identifiers

• HTTP verbs indicate which operation should happen

• We have full CRUD operations on a series of resources

Here’s one I prepared earlier: /public/rest/

Page 59: Web services tutorial

REST as a Religion

56

Beware 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 businessrequirements

• Flamewars will ensue

Instead: "An HTTP Web Service"

Page 60: Web services tutorial

Making Our Service Restful

57

We’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/friends

A specific item is a resource; where you request a list, e.g. /user , this iscalled a collection

Page 61: Web services tutorial

All Requests to index.php

58

We want to push all requests through index.php, there is an .htaccess filethat does this

<IfModule mod_rewrite.c>RewriteEngine OnRewriteBase /

RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule ^(. * )$ index.php/$1 [L]

</IfModule>

/public/rest/.htaccess

Page 62: Web services tutorial

Routing Within Our App

59

So 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

Page 63: Web services tutorial

A Simple Controller

60

Now in UserController we add a GETAction

class 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

Page 64: Web services tutorial

Calling our Service

61

Example 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

Page 65: Web services tutorial

Extending our Service

62

Next we will add something to get the user’s friendshttp://api.local/users/1/friends

class 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

Page 66: Web services tutorial

Hypermedia

63

• 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

Page 67: Web services tutorial

Creating New Records

64

RESTful 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 userheader ( 'HTTP/1.1 201 Created' );header ( 'Location: http://api.local/rest/users/5' );return $new_user;

}

/public/rest/controllers.php

Page 68: Web services tutorial

Incoming POST/PUT Data

65

We 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, it's an array$data = json_decode ( file_get_contents ( 'php://input' ), true );break ;

/public/rest/index.php

Page 69: Web services tutorial

POSTing JSON Data from PHP

66

Adding 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

Page 70: Web services tutorial

Appropriate Status Codes for REST

67

• 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

Page 71: Web services tutorial

Responding to Failure

68

• Use expected response format

• Collate all errors and return

• Help users help themselves

• Be consistent

• Be accurate

Page 72: Web services tutorial

Delivering Services

Page 73: Web services tutorial

Technical Aspects

70

All PHP Best Practices apply equally to APIs

• Source control

• Unit/Integration testing

• Automated deployment

• Monitoring

Reliability and consistency are key

Page 74: Web services tutorial

User Aspects

71

Who 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

Page 75: Web services tutorial

Questions?

Page 76: Web services tutorial

Resources

73

All links are in the bit.ly bundle bit.ly/emRpYT

Page 77: Web services tutorial

Thanks

74

• http://joind.in/talk/view/3461

• http://lornajane.net