working with web services

124
Working With Web Services Rob Richards May 20, 2008 http://xri.net/=rob.richards

Upload: others

Post on 12-Sep-2021

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Working With Web Services

Working With Web ServicesRob Richards

May 20, 2008

http://xri.net/=rob.richards

Page 2: Working With Web Services

• GET / POST

• Restful

• REST

• XML-RPC

• JSON-RPC

• SOAP

Common Types Of Services

2

Page 3: Working With Web Services

GET / POST

• More Service Oriented– Actions are performed on the same/similar endpoints

– Parameters or Body drive actions

– Tend to be more free for all in design

– Perform Read/Write operations

• Any data format supported– XML

– JSON

Examples From Amazon EC2 Servicehttps://ec2.amazonaws.com/?Action=AllocateAddress&AWSAccessKeyId=...

https://ec2.amazonaws.com/?Action=CreateKeyPair&KeyName=example-key-name&AWSAccessKeyId=...

https://ec2.amazonaws.com/?Action=DescribeInstances&AWSAccessKeyId=...

3

Page 4: Working With Web Services

Amazon Simple Queue Service

$url = 'http://queue.amazonaws.com/queue1';$params = array('Action'=>'SendMessage', 'MessageBody' => 'Your%20Message%20Text', 'AWSAccessKeyId'=>'0GS755xyzEXAMPLE', . . .);

$post_body = http_build_query($params);$context_params = array( 'http' => array( 'method' => 'POST', 'header' => 'Content-Type: application/x-www-form-urlencoded', 'content' => $post_body ));$file_context = stream_context_create($context_params);

$results = file_get_contents($url, false, $file_context);var_dump($results);

4

Page 5: Working With Web Services

RESTful

• Generally follow REST guidelines

• Read-only data using HTTP GET

• URL path typically does not refer to resource

• Parameters influence results

Yahoo Image Search

http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=YahooDemo&query=PHP+elephant&output=json

{"ResultSet":{"totalResultsAvailable":"561","totalResultsReturned":10,"firstResultPosition":1,"Result":[{"Title":"php_elephant.jpg","Summary":"php_elephant.jpg","Url":"http:\/\/vizzed.com\/VizzedBoardFiles\/upload\/php_elephant.jpg","ClickUrl":"http:\/\/vizzed.com\/VizzedBoardFiles\/upload\/php_elephant.jpg","RefererUrl":"http:\/\/vizzed.com\/VizzedBoardFiles\/upload","FileSize":7065,"FileFormat":"jpeg","Height":"96","Width":"150","Thumbnail":{"Url":"http:\/\/re3.yt-thm-a01.yimg.com\/image\/25\/m1\/2070796738","Height":"80","Width":"125"}} . . .

5

Page 6: Working With Web Services

Representational State Transfer: REST

• Endpoints are resource identifiers– A resource is any named item

– Resources are identified by URLs

• Architectural style not a standard

• Builds upon standards– HTTP

– URLS

– Mime types

• HTTP methods determine action

• Google APIs are good examples– Calendar

– Spreadsheet

– Notebook

6

Page 7: Working With Web Services

HTTP Methods & Actions

7

HTTP CRUD

POST CREATE

GET RETRIEVE

PUT UPDATE

DELETE DELETE

HTTP CRUD

POST CREATE/UPDATE/DELETE

GET RETRIEVE

PUT CREATE/UPDATE

DELETE DELETE

Formal Operations Relaxed Operations

Page 8: Working With Web Services

REST Retrieve Data

Retrieve private entries from a personal calendarUses HTTP GET

Retrieve All Entries:http://www.google.com/calendar/feeds/<userid>/private/full

Retreive Specific Entry:http://www.google.com/calendar/feeds/<userid>/private/full/cmanvsln9jk5e

Limit To Entries Within Date Range:http://www.google.com/calendar/feeds/<userid>/private/full?start-min=2008-05-01T00:00:00&start-max=2008-05-31T23:59:59

8

Page 9: Working With Web Services

REST: Google Calendar Entry

<entry . . .> <id>http://www.google.com/calendar/feeds/default/private/full/asdc</id> <published>2008-05-13T23:36:58.000Z</published> <updated>2008-05-13T23:44:44.000Z</updated> <category scheme=".../g/2005#kind" term=".../g/2005#event"/> <title type="text">Tennis with John</title> <content type="text">Meet for a quick lesson.</content>. . . <link rel="edit" type="application/atom+xml" href="http://www.google.com/calendar/feeds/default/private/full/asdc/63346405484"/> <author> <name>Rob Richards</name> </author> <gd:comments> <gd:feedLink href="./calendar/feeds/default/private/full/asdc/comments"/> </gd:comments> . . . <gd:where valueString="Rolling Lawn Courts"/></entry>

9

Page 10: Working With Web Services

REST Create Entry

POST Entry Datahttp://www.google.com/calendar/feeds/default/owncalendars/full

• URL Is Same As One Used By Calendar Retrieval• Content-Type is application/atom+xml• Successful Creation

- 201 Created status returned- Newly created Entry returned

• Failure returns other GData Status Code

10

Page 11: Working With Web Services

REST Update Entry

URL used to edit an entry is located in the edit link:<link rel="edit" type="application/atom+xml" href="http://www.google.com/calendar/feeds/default/private/full/asdc/63346405484"/>

HTTP PUT edited entry to edit URL

<entry . . .> <id>http://www.google.com/calendar/feeds/default/private/full/asdc</id> <published>2008-05-13T23:36:58.000Z</published> <updated>2008-05-14T23:44:44.000Z</updated> <category scheme=".../g/2005#kind" term=".../g/2005#event"/> <title type="text">Tennis with John</title> <content type="text">Meet for a quick lesson.</content>. . . <author> <name>Rob Richards</name> </author> . . . <gd:where valueString="Gray Clay Courts"/>

11

Page 13: Working With Web Services

XML-RPC

• XML-based Remote Procedure Call

• Function call is marshaled

• Data structure defines method, types and values

• Parameters and return values are typed

• Defines how the messages is to be transported– HTTP POST

– Required HTTP Headers

• More Tightly Coupled

• Predecessor to SOAP

13

Page 14: Working With Web Services

XML-RPC Request

HTTP POST: http://www.upcdatabase.com/rpc

<?xml version="1.0" encoding="iso-8859-1"?><methodCall> <methodName>lookupUPC</methodName> <params> <param> <value> <string>021000013425</string> </value> </param> </params></methodCall>

14

Page 15: Working With Web Services

<methodResponse> <params> <param> <value> <struct> <member> <name>upc</name> <value> <string>021000013425</string> </value> </member> <member> <name>description</name> <value> <string>SUPER MAC &amp; CHEESE SPONGE BO *</string> </value> </member> <member> <name>size</name> <value> <string>5.5 oz</string> </value> </member> </struct> </value> </param> </params></methodResponse>

XML-RPC Response

15

Page 16: Working With Web Services

JSON-RPC

• Comparable to XML-RPC though using JSON

• In addition to method and parameters, JSON-RPC includes an id property to map requests and responses

• Defines one-way communications (notifications)

• No specific transport protocol required

• HTTP POST most common transport

16

Page 17: Working With Web Services

JSON-RPC Request

HTTP POST:http://www.raboof.com/Projects/Jayrock/Demo.ashx

Content-type: application/json

{"method":"total","params":{"values":[1,2,3]},"id":55}

$data = array("method"=>"total", "params"=>array("values"=>array(1,2,3)), "id" => 55);echo json_encode($data)."\n";$json = json_encode($data)

17

Page 18: Working With Web Services

JSON-RPC Response

{"id":55,"result":6}

$objResult = json_decode($results); echo $obResult->result."\n";

18

Page 19: Working With Web Services

SOAP

• SOAP stands for ABSOLUTELY NOTHING!

• Can be RPC or Message based

• Strong data typing

• Designed for interoperability

• Can be simple to use

• Allows for advanced communications– Standard security mechanisms

– Message delivery guarantee

– Additional out of band information

– Addressing and callback capabilities

19

Page 20: Working With Web Services

SOAP Message

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:SendMessage xmlns:m="urn:yahoo:ymws"> <message> <to> <email>[email protected]</email> </to> <from> <email>[email protected]</email> </from> <simplebody> <text>this is a test</text> </simplebody> <subject>test</subject> </message> </m:SendMessage> </SOAP-ENV:Body></SOAP-ENV:Envelope>

20

Page 21: Working With Web Services

SOAP Response

<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <SendMessageResponse/> </SOAP-ENV:Body></SOAP-ENV:Envelope>

21

Page 22: Working With Web Services

Deciding Upon A Service

With All The Different Types Of Services, How Do You Decide

What To Use?

?22

Page 23: Working With Web Services

Intended Audience

• Exposing To The Masses

• Internal Developers

• Business Partners

• Multiple Audiences

23

Page 24: Working With Web Services

Security Implications

• Do you need to protect your data?

• Do users need to be authenticated?

• To what level do you need protection?

• Are multiple parties involved?

• Does the data pass through multiple systems?

• Do you need granularity?

24

Page 25: Working With Web Services

What Is The Purpose?

• Reduce system maintenance?

• Expose existing logic as services?

• Expose logic from legacy systems?

• Aggregate functionality?

25

Page 26: Working With Web Services

Any Curveballs?

• Two-phase commits

• Asynchronous Messaging

• Legacy System Protocols

• Multi-System Involvement

26

Page 27: Working With Web Services

Let’s Get Our Hands Dirty!

Page 28: Working With Web Services

Helpful Tools

• Eclipse– WSDL Editor

– XML / XSD Editors & Validators

• Misc. XML Editors– XML NotePad 2007 (Microsoft)

– XML Spy (Altova)

• soapUI– http://www.soapui.org

– Multiple platforms / Free & enhanced Pro versions

• SOAPSonar– http://www.crosschecknet.com

– Windows only / Free and Professional versions

28

Page 29: Working With Web Services

Yahoo Product Search

// URL to Product Search service$url = 'http://shopping.yahooapis.com/ShoppingService/V3/productSearch?';

// The query is separate here as the terms must be encoded.$url .= 'query='.rawurlencode('linksys');

// Complete the URL with App ID, limit to 1 result and start at second record$url .= "&appid=zzz&results=2&start=2";

$data = file_get_contents($url);

echo $data;

29

Page 30: Working With Web Services

Not So Simple

<?xml version="1.0" encoding="utf-8"?><Error xmlns="urn:yahoo:api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:yahoo:api http://api.yahoo.com/Api/V1/error.xsd">The following errors were detected:<Message>User-agent not valid</Message></Error>

30

Page 31: Working With Web Services

Set The User Agent

$context_params = array( 'http' => array( 'user_agent' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)' ));

$file_context = stream_context_create($context_params);

$data = file_get_contents($url, false, $file_context);

echo $data;

31

Page 32: Working With Web Services

Yahoo Results

<ProductSearch xmlns="urn:yahoo:prods" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:yahoo:prods http://shopping.yahooapis.com/shoppingservice/v3/productsearch.xsd"> <Categories totalSubcategories="1" type="Can"> <SubCategory> <Title>Computers &amp; Software</Title> <Value>1can1acp</Value> <NumberOfProducts>7196</NumberOfProducts> <SubCategory> <Title>Networking</Title> <Value>1can1gnetwork</Value> <NumberOfProducts>5308</NumberOfProducts> <SubCategory> <Title>Network Adapters</Title> <Value>1can1cnetworkZZZ5Fadapter</Value>

32

Page 33: Working With Web Services

We Want To Use SimpleXML Directly!

if ($sxe = simplexml_load_file($url)) { echo $sxe->Categories->SubCategory->Title;}

PHP Notice: Trying to get property of non-object in /Users/rrichards/tests/php/yahoo/shop.php on line 23

33

Page 34: Working With Web Services

Stream Contexts and XML

$context_params = array( 'http' => array( 'user_agent' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)' ));$xml_context = stream_context_create($context_params);

libxml_set_streams_context($xml_context);

if ($sxe = simplexml_load_file($url)) { echo $sxe->Categories->SubCategory->Title;}

Computers & Software

34

Page 35: Working With Web Services

Google Calendar

35

Page 36: Working With Web Services

Google Calendar Login

$url = 'https://www.google.com/accounts/ClientLogin';

$params = array('Email'=>'[email protected]', 'Passwd' => <password>, 'source'=>'phpwebsvc-1', 'service' => 'cl');

$post_body = http_build_query($params);

$context_params = array( 'http' => array( 'method' => 'POST', 'header' => 'Content-Type: application/x-www-form-urlencoded', 'content' => $post_body ));$file_context = stream_context_create($context_params);

$results = file_get_contents($url, false, $file_context);

36

Page 37: Working With Web Services

Google Calendar Login Using ext/http

$url = 'https://www.google.com/accounts/ClientLogin';$params = array('Email'=>'[email protected]', 'Passwd' => <password>, 'source'=>'phpwebsvc-1', 'service' => 'cl');

$post_body = http_build_query($params);

$req->setBody($post_body);

$req->setContentType('application/x-www-form-urlencoded');

$msg = $req->send();

$results = $msg->getBody();

37

Page 38: Working With Web Services

Google Calendar Our Login

SID=DQAAAIkAAAAnSKcLgj-iO123456789012345123456789012345gHq_QlR2ruTbbDsXoB5H2OWsgg-E4tEeq7U23o1234567890123455v9Nsf6AkYdf1234567890123458eCEjr867-5dO3Needaa6xoltHi-ryWGKrui1234567890123455U4x9WN-vafQHx3JanyysLSID=DQAAAIoAAACEji868ECURZS3GDZsfls8nl-3O5WoiPzboDD2lwJkAmcQ0Sbyg3SPAe0yxiJa123456789012345yk9123456789012345jaYrUxHerwl1wD4Uz603z1234567890123457OkD4dTewAw6YVQRMin123234567890123458xpJ0rAx1saURz9RKTKbjen2AoAuth=DQAAAIoAAACEji123456789012345ls8nl-3O5WoiPzboDD2123456789012345PAe0yxiJa7Tfzeyk9eB4B0hMgT5t_1234567890123454ejaYrUxHekJqc4fe7SaZYd123456789012345SjUK1kLrCualqsZTpBpS-T123456789012345g3RobFeGDh2Yv-68nHffw

38

Page 39: Working With Web Services

Get Auth Token

$tokens = split("\n", $results);foreach ($tokens AS $current) { $artemp = split("=", $current); if ($artemp[0] == 'Auth') { $token = $artemp[1]; break; }}

39

Page 40: Working With Web Services

Get Our Calendar Entries

$url = 'http://www.google.com/calendar/feeds/cdatazone.org%40gmail.com/private/full';

$req = new HttpRequest($url, HttpRequest::METH_GET);

$req->addHeaders(array('Authorization' => "GoogleLogin auth=$token"));

$req->setOptions(array('redirect'=>1));

$msg = $req->send();

$cal = simplexml_load_string( $msg->getBody() );

echo $cal->asXML();

40

Page 41: Working With Web Services

Our Calendar Entries

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="...rchrss/1.0/" . . .> <id>http://www.google.com/calendar/feeds/cdatazone.org%40gmail.com/private/full</id> <openSearch:totalResults>3</openSearch:totalResults>... <entry> <id>http://www.google.com/calendar/feeds/cdatazone.org%40gmail.com/private/full/i3jg8t7ggoaj5l99dafue9ap1g</id> <published>2008-05-17T16:23:49.000Z</published> <updated>2008-05-17T16:24:29.000Z</updated> <title type="text">Working With Web Services</title> <link rel="self" type="application/atom+xml" href="http://www.google.com/calendar/feeds/cdatazone.org%40gmail.com/private/full/i3jg8t7ggoaj5l99dafue9ap1g"/> <link rel="edit" ...href="http://www.google.com/calendar/feeds/cdatazone.org%40gmail.com/private/full/i3jg8t7ggoaj5l99dafue9ap1g/63346724669"/>. . . </entry></feed>

41

Page 42: Working With Web Services

New Entry

<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'> <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event' /> <title type='text'>Cocktails</title> <content type='text'>Mashery cocktail event</content> <gd:transparency value='http://schemas.google.com/g/2005#event.opaque' /> <gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed' /> <gd:where valueString='The Bar'/> <gd:when startTime='2008-05-22T20:30:00.000Z' endTime='2008-05-22T22:30:00.000Z' /></entry>

42

Page 43: Working With Web Services

Create The Entry

$url = 'http://www.google.com/calendar/feeds/cdatazone.org%40gmail.com/private/full';

$req = new HttpRequest($url, HttpRequest::METH_POST);

$req->setBody($myentry);

$req->setContentType('application/atom+xml');$req->setOptions(array('redirect'=>3));

$req->addHeaders(array('Authorization' => "GoogleLogin auth=$token"));

$msg = $req->send();

echo $msg->getBody();

43

Page 44: Working With Web Services

Now What???

No Error, But No New Entry

44

Page 45: Working With Web Services

Inspecting The Transaction

$req = new HttpRequest($url, HttpRequest::METH_POST);$req->setBody($myentry);

$req->setContentType('application/atom+xml');$req->setOptions(array('redirect'=>3));$req->addHeaders(array('Authorization' => "GoogleLogin auth=$token"));

$msg = $req->send();

echo $msg->getBody();

var_dump($msg->getParentMessage());

45

Page 46: Working With Web Services

Inspecting The Transaction

. . . ["responseStatus:protected"]=> string(17) "Moved Temporarily" ["responseCode:protected"]=> int(302) ["httpVersion:protected"]=> float(1.1) ["headers:protected"]=> array(8) { ["Location"]=> string(91) "http://www.google.com/calendar/feeds/default/private/full?gsessionid=ulqFh1tY96KwH2uR8QBKYw" ["Content-Type"]=> string(24) "text/html; charset=UTF-8" ["Date"]=> string(29) "Sat, 17 May 2008 17:04:23 GMT" ["Expires"]=> string(29) "Sat, 17 May 2008 17:04:23 GMT" ["Cache-Control"]=> string(18) "private, max-age=0" ["Content-Length"]=> . . .

46

Page 47: Working With Web Services

Fixed The URL

$url = 'http://www.google.com/calendar/feeds/default/private/full?gsessionid=ulqFh1tY96KwH2uR8QBKYw';

$req = new HttpRequest($url, HttpRequest::METH_POST);

$req->setBody($myentry);

$req->setContentType('application/atom+xml');$req->setOptions(array('redirect'=>3));

$req->addHeaders(array('Authorization' => "GoogleLogin auth=$token"));

$msg = $req->send();

echo $msg->getBody();

47

Page 48: Working With Web Services

Our New Entry

<entry xmlns="http://www.w3.org/2005/Atom" ...> <id>http://www.google.com/calendar/feeds/cdatazone.org%40gmail.com/private/full/ns4d6037c1kvrm4i5ena2oo9h4</id> <title type="text">Cocktails</title> <content type="text">Mashery sponsored cocktails</content>... <link rel="edit" type="application/atom+xml" href="http://www.google.com/calendar/feeds/cdatazone.org%40gmail.com/private/full/ns4d6037c1kvrm4i5ena2oo9h4/63346727478"/>... <gCal:sequence value="0"/> <gd:when startTime="2008-05-22T16:30:00.000-04:00" endTime="2008-05-22T18:30:00.000-04:00"/> <gd:who rel="http://schemas.google.com/g/2005#event.organizer" valueString="Rob Richards" email="[email protected]"/> <gd:where valueString="The Bar"/></entry>

48

Page 49: Working With Web Services

Our Calendar

49

Page 50: Working With Web Services

Fix The Content, Time & Location

$url = 'http://www.google.com/calendar/feeds/default/private/full? start-min=2008-05-22&start-max=2008-05-23&q=Cocktails';$req = new HttpRequest($url, HttpRequest::METH_GET);$req->setContentType('application/atom+xml');$req->setOptions(array('redirect'=>3));$req->addHeaders(array('Authorization' => "GoogleLogin auth=$token"));$msg = $req->send();

if ($cal = simplexml_load_string( $msg->getBody() )) { foreach ($cal->entry AS $entry) { if ($entry->title == 'Cocktails') { $domentry = dom_import_simplexml($entry); $dom = new DOMDocument(); $myEntry = $dom->importNode($domentry, TRUE); $dom->appendChild($myEntry); } }}

50

Page 51: Working With Web Services

What Did We Find? (Summarized)

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005" xmlns:gCal="http://schemas.google.com/gCal/2005"> <id>http://www.google.com/calendar/feeds/default/private/full/ns4d6037c1kvrm4i5ena2oo9h4</id> <title type="text">Cocktails</title> <content type="text">Mashery sponsored cocktails</content> <link rel="edit" type="application/atom+xml" href="http://www.google.com/calendar/feeds/default/private/full/ns4d6037c1kvrm4i5ena2oo9h4/63346727478"/> <gCal:uid value="[email protected]"/> <gCal:sequence value="0"/> <gd:when startTime="2008-05-22T16:30:00.000-04:00" endTime="2008-05-22T18:30:00.000-04:00"/> <gd:who rel="http://schemas.google.com/g/2005#event.organizer" valueString="Rob Richards" email="[email protected]"/> <gd:where valueString="The Bar"/></entry>

51

Page 52: Working With Web Services

Edit The Entry

$gSession = '?gsessionid=3IqBQirtNrir7o4nNTCSDA';$gdNS = 'http://schemas.google.com/g/2005';

$entry = simplexml_import_dom($dom);$entry->content = 'Mashery cocktail event';

$when = $entry->children($gdNS)->when->attributes();$when['startTime'] = '2008-05-22T17:30:00.000-05:00';$when['endTime'] = '2008-05-22T19:30:00.000-05:00';

$where = $entry->children($gdNS)->where->attributes();$where['valueString'] = '11th Floor';

foreach ($entry->link AS $link) { if ($link['rel'] == 'edit') { $updateUrl = $link['href'] . $gSession; $contentType = $link['type']; }}

52

Page 53: Working With Web Services

Edited Entry (Summarized)

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005" xmlns:gCal="http://schemas.google.com/gCal/2005"> <id>http://www.google.com/calendar/feeds/default/private/full/ns4d6037c1kvrm4i5ena2oo9h4</id> <title type="text">Cocktails</title> <content type="text">Mashery cocktail event</content> <link rel="edit" type="application/atom+xml" href="http://www.google.com/calendar/feeds/default/private/full/ns4d6037c1kvrm4i5ena2oo9h4/63346727478"/> <gCal:uid value="[email protected]"/> <gCal:sequence value="0"/> <gd:when startTime="2008-05-21T17:30:00.000-05:00" endTime="2008-05-21T19:30:00.000-05:00"/> <gd:who rel="http://schemas.google.com/g/2005#event.organizer" valueString="Rob Richards" email="[email protected]"/> <gd:where valueString="11th Floor"/></entry>

53

Page 54: Working With Web Services

Call The Update

$req = new HttpRequest($updateUrl, HttpRequest::METH_PUT);

$req->setPutData($entry->asXML());$req->setContentType($contentType);

$req->setOptions(array('redirect'=>3));

$req->addHeaders(array('Authorization' => "GoogleLogin auth=$token"));$msg = $req->send();

echo $msg->getBody();

54

Page 55: Working With Web Services

Updated Calendar

55

Page 56: Working With Web Services

Working With SOAP

Page 57: Working With Web Services

• Web Service Inspection– WSDL Inspector

– HTTP data inspection (request & response)

• Web Service Invocation– Automatic Request generation

– Authentication support (Basic, Digest, WS-Security)

– Custom HTTP Header support

• Web Service Development and Validation

• Web Service Functional Testing

• Web Service Load Testing

• Web Service Simulation

soapUI Features

57

Page 58: Working With Web Services

Working With soapUI

58

Page 59: Working With Web Services

Eclipse WSDL Editing

59

Page 60: Working With Web Services

Eclipse WSDL Editing

60

Page 61: Working With Web Services

Eclipse XML Schema Editing

61

Page 62: Working With Web Services

OpenCalais Service

• http://www.opencalais.com/

• Powered by Reuters

• Extracts semantic metadata from documents

• Results returned in RDF (Resource Description Framework) format

• Become part of the Semantic Web

• Service is Free!

62

Page 63: Working With Web Services

Inspect The API

$wsdl = 'http://api.opencalais.com/enlighten/?wsdl';

$client = new SOAPClient($wsdl);

$types = $client->__getTypes();foreach ($types AS $type) { echo $type."\n";}echo "\n\n";

$functions = $client->__getFunctions();foreach ($functions AS $func) { echo $func."\n";}

63

Page 64: Working With Web Services

OpenCalais API

struct Enlighten { string licenseID; string content; string paramsXML;}struct EnlightenResponse { string EnlightenResult;}

EnlightenResponse Enlighten(Enlighten $parameters)string Enlighten(string $licenseID, string $content, string $paramsXML)

64

Page 65: Working With Web Services

Working With Structs

From WSDLstruct Enlighten { string licenseID; string content; string paramsXML;}

IN PHP

array('licenseID' => x, 'content' => y, 'paramsXML'=>z)

class Enlighten { public $licenseID; public $content; public $paramsXML;}

65

Page 66: Working With Web Services

Making The Request

$_content = <<<EOXML<DOCUMENT> <TYPE>NEWS</TYPE> <SOURCEURL>http://biz.yahoo..../airlines_damages_1.html </SOURCEURL> <TITLE> US OKs Airline Damage Limits Removal </TITLE> <DATE> Friday September 5, 5:03 pm ET </DATE> <SOURCE> Reuters </SOURCE> <BODY> WASHINGTON (Reuters) - The United States finalized a treatyeffect in... overseas to pursue damages. "The (treaty) will ensure far more humane treatment of the victims of international airline accidents and their families than is possible under the current system," TransportationSecretary Norman Mineta said in a statement. The newly ratified accord replaces the Warsaw Convention of 1929, which has been considered outdated and, in many cases,unfair. </BODY></DOCUMENT>EOXML;

66

Page 67: Working With Web Services

Making The Request

$_ paramsXML = <<<EOXML

<c:params xmlns:c="http://s.opencalais.com/1/pred/"

xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

<c:processingDirectives c:contentType="text/txt"

c:outputFormat="xml/rdf" />

<c:userDirectives c:allowDistribution="true" c:allowSearch="true"

c:externalID="17cabs901" c:submitter="ABC" />

<c:externalMetadata />

</c:params>

EOXML;

67

Page 68: Working With Web Services

Making The Request

$wsdl = 'http://api.opencalais.com/enlighten/?wsdl';

$client = new SOAPClient($wsdl);

$result = $client->Enlighten( array( 'licenseID' => '<mylicenseID>', 'content' => $_content, 'paramsXML' => $_paramsXML ));

echo $result->EnlightenResult;

68

Page 69: Working With Web Services

The Response (Edited)

<rdf:RDF xmlns:rdf="...9/02/22-rdf-syntax-ns#" xmlns:c=".../1/pred/">... <rdf:Description rdf:about=".../37225f05-d55e-3512-9808-4ff11370db12"> <rdf:type rdf:resource="http://s.opencalais.com/1/type/em/e/Person"/> <c:name>Norman Mineta</c:name> <c:persontype>political</c:persontype> </rdf:Description> <rdf:Description rdf:about="...6c89-9a70-331e-b113-12546ced5d10/Instance/1"> <rdf:type rdf:resource="http://s.opencalais.com/1/type/sys/InstanceInfo"/> <c:docId rdf:resource="...6c89-9a70-331e-b113-12546ced5d10"/> <c:subject rdf:resource="..../37225f05-d55e-3512-9808-4ff11370db12"/><!--Person: Norman Mineta--> <c:detection>[the current system," Transportation Secretary ]Norman Mineta[ said in a statement. The newly ratified accord]</c:detection> <c:offset>1765</c:offset> <c:length>13</c:length> </rdf:Description> ...</rdf:RDF>

69

Page 70: Working With Web Services

What About the Other Method Signature?

$wsdl = 'http://api.opencalais.com/enlighten/?wsdl';

try {

$client = new SOAPClient($wsdl);

$result = $client->Enlighten('<mylicenseID>', $_content,

$_paramsXML);

echo $result->EnlightenResult;

} catch (Exception $e) {

echo "Fault: " . $e->faultstring."\n";

echo "Code: " . $e->faultcode."\n";

}

70

Page 71: Working With Web Services

When Things Go Wrong...

Fault: ForbiddenCode: HTTP

71

Page 72: Working With Web Services

Enter Debug Mode

$wsdl = 'http://api.opencalais.com/enlighten/?wsdl';

$options = array('trace' => 1);

try { $client = new SOAPClient($wsdl, $options);

$result = $client->Enlighten('<mylicenseID>', $_content, $_paramsXML); echo $result->EnlightenResult;} catch (Exception $e) {

echo $client->__getLastRequest();

}

72

Page 73: Working With Web Services

Our Request

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://clearforest.com/"> <SOAP-ENV:Body> <ns1:Enlighten/>

<param1>&lt;DOCUMENT&gt;

&lt;TYPE&gt;NEWS&lt;/TYPE&gt;

&lt;SOURCEURL&gt; http://biz.yahoo.com/rb/030905/airlines_damages_1.html &lt;/SOURCEURL&gt;

...</param1>

<param2>&lt;c:params xmlns:c="http://s.opencalais.com/1/pred/" ...</param2>

</SOAP-ENV:Body></SOAP-ENV:Envelope>

73

Page 74: Working With Web Services

Let’s Try soapUI

74

Page 75: Working With Web Services

Other Debugging Functions

SOAPClient::__getLastRequest()– Get the raw SOAP request

SOAPClient::__getLastRequestHeaders()– Get the HTTP headers sent with the request

SOAPClient::__getLastResponse()– Get the response from the server

SOAPClient::__getLAstResponseHeaders()– Get the HTTP headers received from the server

75

Page 76: Working With Web Services

Server Sided SOAP

Page 77: Working With Web Services

DISABLE WSDL CACHINGWHEN DEVELOPING!

ini_set("soap.wsdl_cache_enabled", "0");

Disable That Cache

77

Page 78: Working With Web Services

Generating The WSDL

• Integrated Generators– Services_Webservices

• http://pear.php.net/package/Services_Webservice

– PRADO

• http://pradosoft.com/demos/quickstart/?page=Services.SoapService

– WSO2 WSF/PHP (http://wso2.org/projects/wsf/php)

• External Tools– Eclipse WSDL Editor in Web Tools Platform (WTP)

– Zend Studio (http://www.zend.com/en/products/studio/)

78

Page 79: Working With Web Services

Services_Webservice WSDL Generation

include_once('Services/Webservice.php'); class myService extends Services_Webservice { /** * Says "Hello!" * * @param int * @return string */ public function hello($i ) { //create some logic here return 'myString'; }

79

Page 80: Working With Web Services

Serving Up The WSDL

Server Script: myserv.php

/* Helper functions here */$soapSrv = new SoapServer('helloworld.wsdl');

/* Register functions */$soapSrv->handle();

Using the SoapClient:$soapClient = new SoapClient( 'http://localhost/myserv.php?wsdl');

80

Page 81: Working With Web Services

Handling Requests

• The typical method to process a SOAP request– $soapServer->handle();

• Request may be passed to handler– $soapServer->handle($request);

• Passing in the request can be handy– You can be guaranteed of the same request while debugging

– Debugging can be performed via CLI

– Requests can be modified prior to being processed

81

Page 82: Working With Web Services

Handling Requests: Debugging

/* create the initial request to be re-used */$request = file_get_contents("php://input");file_save_contents('debugging.xml', $request);

/* retrieve saved request on subsequent calls$request = file_get_contents('debugging.xml');*/

$server = new SoapServer($wsdl);/* Setup function handlers */$server->handle($request);

82

Page 83: Working With Web Services

Creating Our Service

Page 84: Working With Web Services

class cSayHello { private $date = NULL;

function __construct($date) { $this->_date = $date; }

function greet($name, $age) { return "Hello $name. Today is" . $this->_date . ". You are $age"; }}

Our Logic

84

Page 85: Working With Web Services

Skeleton Server

ini_set("soap.wsdl_cache_enabled", "0");class cSayHello { private $date = NULL;

function __construct($date) { $this->_date = $date; }

function greet($name, $age) { return "Hello $name. Today is" . $this->_date . ". You are $age"; }}

$srv = new SOAPServer();$srv->setClass('cSayHello', date());

$srv->handle();

85

Page 86: Working With Web Services

Create The WSDL

86

Page 87: Working With Web Services

Creating The WSDL

87

Page 88: Working With Web Services

Creating The WSDL

88

Page 89: Working With Web Services

Calling The Client

PHP Fatal error: Uncaught SoapFault exception: [Client] looks like we got no XML document in /Users/rrichards/Sites/fizzer/tek/PHPTek/demo/soapclient-step1.php:4Stack trace:#0 [internal function]: SoapClient->__call('greet', Array)#1 /Users/rrichards/Sites/fizzer/tek/PHPTek/demo/soapclient-step1.php(4): SoapClient->greet(Array)#2 {main} thrown in /Users/rrichards/Sites/fizzer/tek/PHPTek/demo/soapclient-step1.php on line 4

89

Page 90: Working With Web Services

Debugging The Server

ini_set("soap.wsdl_cache_enabled", "0");

//file_put_contents('/tmp/myclient.xml', file_get_contents('php://input'));$input = file_get_contents('/tmp/myclient.xml');class cSayHello { private $date = NULL;

function __construct($date) { $this->_date = $date; }

function greet($name, $age) { return "Hello $name. Today is" . $this->_date . ". You are $age"; }}

$srv = new SOAPServer('myservice.wsdl');$srv->setClass('cSayHello', date());

$srv->handle($input);

90

Page 91: Working With Web Services

Execute The Server Code

PHP Warning: date() expects at least 1 parameter, 0 given in /Users/rrichards/Sites/fizzer/tek/PHPTek/demo/soapsrv.php on line 23

PHP Warning: Missing argument 2 for cSayHello::greet() in /Users/rrichards/Sites/fizzer/tek/PHPTek/demo/soapsrv.php on line 15

91

Page 92: Working With Web Services

Fix Server Code

ini_set("soap.wsdl_cache_enabled", "0");$input = file_get_contents('/tmp/mysoapclient.xml');

class cSayHello { private $date = NULL;

function __construct($date) { $this->_date = $date; }

function greet($objGreet) { return "Hello $objGreet->name. Today is" . $this->_date . ". You are $objGreet->age"; }}

$srv = new SOAPServer('myservice.wsdl');$srv->setClass('cSayHello', date('F j, Y'));

$srv->handle($input);

92

Page 93: Working With Web Services

The Server Response

<?xml version="1.0" encoding="UTF-8"?>

<SOAP-ENV:Envelope

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Body>

<parameters>Hello Rob. Today isMay 18, 2008. You are 37</parameters>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

93

Page 94: Working With Web Services

Service Component Architecture (SCA)

Page 95: Working With Web Services

• Project by the Open Service Oriented Architecture (OSOA) collaboration - http://www.osoa.org/display/Main/Home

• http://www.osoa.org/display/PHP/SOA+PHP+Homepage

• Combined with the SDO extension

• Pecl repository: http://pecl.php.net/package/SCA_SDO

• Allows the developer to concentrate on the business logic rather than how it is all connected together

Service Component Architecture (SCA)

95

Page 96: Working With Web Services

SCA Benefits

• Support multiple protocols without additional coding

• Re-usable code through the separation of business logic and communication layers

• Local and remote integration transparency

• Simplify consumption and exposure of web services

96

Page 97: Working With Web Services

SCA Components

97

BusinessLogic

Annotations

Binding Types

Data Types

InterfaceDescription

SOAP Request

JSON Request

REST Request

Developer’sResponsibility

Page 98: Working With Web Services

SCA Component

include "SCA/SCA.php";

/** * @service * @binding.soap * @binding.jsonrpc * @binding.rest.rpc */

class RobsService {

/** Find out who I am. * @return string Who I am. */ public function whoAmI() { return "I am Rob Richards"; } }

98

Page 99: Working With Web Services

Calling The Component

include "SCA/SCA.php"; $url = 'http://localhost/robsService.php';

/* Use SOAP Binding */ $robservice = SCA::getService($url.'?wsdl'); $whoami = $robservice->whoAmI();

/* Use JSON Binding */ $robservice = SCA::getService($url.'?smd'); $whoami = $robservice->whoAmI();

/* Use Native SOAP */ $client = new SoapClient($url.'?wsdl'); $whoami = $client->whoAmI();

/* Use RESTful Call */ $whoami = file_get_contents($url.'/whoAmI');

/* Use Local Binding */ $robservice = SCA::getService('/home/rrichards/robweb/robsService.php'); $whoami = $robservice->whoAmI();

99

Page 100: Working With Web Services

Complex Types

include "SCA/SCA.php";

/** * @service * @binding.soap * @binding.jsonrpc * @types urn::people PeopleTypes.xsd*/

100

Page 101: Working With Web Services

Complex Types

<?xml version="1.0" encoding="UTF-8"?>

<schema targetNamespace="urn::people" elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="urn::people">

<complexType name="PersonType">

<sequence>

<element name="Name" type="string"></element>

<element name="ID" type="string"></element>

<element name="TimeStamp" type="string"></element>

</sequence>

</complexType>

</schema>

101

Page 102: Working With Web Services

Creating The XML Schema

102

Page 103: Working With Web Services

Creating The XML Schema

103

Page 104: Working With Web Services

Finishing Off The Component

class ComplexService {

/** Find out who I am. * @param int $id My ID * @return PersonType urn::people Who I am. */ public function whoAmI($id) { $person = SCA::createDataObject('urn::people', 'PersonType'); $person->Name = 'Rob Richards'; $person->ID = $id; $person->TimeStamp = time(); return $person; } }

104

Page 105: Working With Web Services

Calling The Component

$url = 'http://fizzer/tek/PHPTek/SCA/ComplexService.php';

$complexservice = SCA::getService($url.'?wsdl'); $whoami = $complexservice->whoAmI(12);

var_dump($whoami);

object(SDO_DataObjectImpl)#11 (3) { ["Name"]=> string(12) "Rob Richards" ["ID"]=> string(2) "12" ["TimeStamp"]=> string(10) "1211136763"}

105

Page 106: Working With Web Services

Referencing Components

class ReferenceService { /** * Get The WhoAmI from robsService * * @reference * @binding.php robsService.php */ public $robs_service;

106

Page 107: Working With Web Services

Referencing Components (cont’d)

/** Find out who I am. * @param int $id My ID * @return PersonType urn::people Who I am. */ public function whoAmI($id) { $person = SCA::createDataObject('urn::people', 'PersonType'); $person->Name = $this->robs_service->whoAmI(); $person->ID = $id; $person->TimeStamp = time(); return $person; } }

107

Page 108: Working With Web Services

Calling New Component

$url = 'http://fizzer/tek/PHPTek/SCA/ReferenceService.php';

$referenceservice = SCA::getService($url.'?wsdl'); $whoami = $referenceservice->whoAmI(12);

var_dump($whoami);

object(SDO_DataObjectImpl)#16 (3) { ["Name"]=> string(17) "I am Rob Richards" ["ID"]=> string(2) "12" ["TimeStamp"]=> string(10) "1211136763"}

108

Page 109: Working With Web Services

SCA: More Information

• Where To Get It– PECL package SCA_SDO

– http://pecl.php.net/sca_sdo

• Documentation, Wiki, Examples– PHP Manual SCA and SDO XML Data Access Service

– Open Service Oriented Architecture http://www.osoa.org/display/PHP/

• Mail List – http://groups.google.com/group/phpsoa

109

Page 110: Working With Web Services

WSO2 Web Services Framework for PHP

(WSO2 WSF/PHP)http://wso2.org/projects/wsf/php

Page 111: Working With Web Services

• Web Service Provider and Consumer– SOAP

– REST

• WS-* Support– WS-Addressing

– WS-Security / WS-SecurityPolicy

– WS-ReliableMessaging

• MTOM Support for attachments

• WSDL Generation

• PHP Class generation from WSDL

WSO2 WSF/PHP

111

Page 112: Working With Web Services

Raw Request

$client = new WSClient(array("to"=> "http://172.16.183.129/transpers.php"));

$message =<<< EOXML<ns1:getPerson xmlns:ns1="http://www.example.org/transformer/"> <fname>Joe</fname> <lname>Schmoe</lname></ns1:getPerson>EOXML;

$res = $client->request($message);var_dump($res);

112

Page 113: Working With Web Services

WSDL Request

$client = new WSClient(array("wsdl"=> "http://172.16.183.129/transformer.wsdl"));

$proxy = $client->getProxy();

$myperson = array('fname' => 'Joe', 'lname' => 'Schmoe');

$res = $proxy->getPerson($myperson);var_dump($res);

113

Page 114: Working With Web Services

Raw Response

function getPerson($message) { $sxe = simplexml_load_string($message->str);

$response = “<getPersonResponse> <fullname>{$sxe->fname} {$sxe->lname}</fullname> <age>”.rand(18,100).”</age>. <sex>”.(rand(0,1)?'M':'F').”</sex> </getPersonResponse>”; return new WSMessage($response);}

$soapSrv = new WSService(array("operations" => array("getPerson")));$soapSrv->reply();

114

Page 115: Working With Web Services

WSDL Response

function getPersonfunc($fname, $lname) { return array('fullname' => $fname." ".$lname, 'age' => rand(18,100), 'sex' => (rand(0,1)?'M':'F'));}

$operations = array("getPerson"=>"getPersonfunc");$opParams = array("getPersonfunc"=>"MIXED");

$service = new WSService(array("wsdl"=>"transformer2.wsdl", "operations" => $operations, "opParams"=>$opParams)); $service->reply();

115

Page 116: Working With Web Services

REST

$requestPayloadString = "<webSearch><appid>myDemo</appid><query>Pro PHP XML</query><form/></webSearch>";

try { $client = new WSClient( array("to"=>"http://search.yahooapis.com/WebSearchService/V1/webSearch", "HTTPMethod"=>GET, "useSOAP"=>FALSE));

$responseMessage = $client->request($requestPayloadString); $results = simplexml_load_string($responseMessage->str);

echo 'Total Results: '.$results['totalResultsAvailable']."\n\n";

} catch (WSFault $e) { echo $e->Reason;}

116

Page 117: Working With Web Services

Advanced Usage

$randNum = (rand()%99);

$reqDate = mktime(0,0,0,date("m"),date("d")+14,date("Y"));$reqDateStr = date("Y/m/d", $reqDate); /* The payload string*/$requestPayloadString = <<<XML <po:Order xmlns:po="http://www.back_packers.com/ws/purchaseorder"> <po:OrderId>po-$randNum</po:OrderId> <po:ReqDate>$reqDateStr</po:ReqDate> <po:Design> <po:FileName>design.jpg</po:FileName> <po:Image><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:myid1"></xop:Include></po:Image> </po:Design> </po:Order>XML;

117

Page 118: Working With Web Services

Attachments

try { /* Load the design*/ $f = file_get_contents("./design.jpg"); /* Build the message*/ $requestMessage = new WSMessage($requestPayloadString, array("to" => "http://localhost/store/manuf_service.php", "action" => "http://www.back_packers.com/purchaseOrder", "attachments" => array("myid1" => $f)));

118

Page 119: Working With Web Services

Policy & WS-SecurityPolicy

// Use WS-Policy File$policy_xml = file_get_contents("policy.xml");//$policy = new WSPolicy($policy_xml);

// Use policy options$policy = new WSPolicy( array( "security" => array("encrypt"=>TRUE, "sign"=>TRUE, "algorithmSuite" => "Basic256Rsa15", "protectionOrder" => "EncryptBeforeSigning", "encryptSignature" => true, "includeTimeStamp" => true)));

119

Page 120: Working With Web Services

WS-SecurityPolicy

</sp:RecipientToken> <sp:AlgorithmSuite> <wsp:Policy> <sp:Basic256Rsa15/> </wsp:Policy> </sp:AlgorithmSuite> <sp:Layout> <wsp:Policy> <sp:Strict/> </wsp:Policy> </sp:Layout> <sp:IncludeTimestamp/> <sp:EncryptSignature/> </wsp:Policy>

120

Page 121: Working With Web Services

WS-Security

$rec_cert = ws_get_cert_from_file("bob_cert.cert"); $my_cert = ws_get_cert_from_file("alice_cert.cert"); $my_key = ws_get_key_from_file("alice_key.pem");

/* Ceate a security token with reqd configurations*/ $sec_token = new WSSecurityToken(array("user" => "Alice", "password" => "abcd!1234", "passwordType" => "Digest", "privateKey" => $my_key, "certificate" => $my_cert, "receiverCertificate" => $rec_cert));

121

Page 122: Working With Web Services

Making The Request

/* Create a new client*/ $client = new WSClient(array("useWSA" => TRUE, "useMTOM" => FALSE, "policy" => $policy, "securityToken" => $sec_token)); /* Request*/ $responseMessage = $client->request($requestMessage); /* Print the response*/ echo $responseMessage->str;

} catch (WSFault $e) { echo $e->Reason;}

122

Page 123: Working With Web Services

Working With Web Services

Rob Richards

http://www.cdatazone.orghttp://xri.net/=rob.richards

Page 124: Working With Web Services

We Are Hiring PHP & AJAX Developers Contact us: [email protected]

OPEN TO ALL We want to meet you! Please join us for complimentary pizza

and beer (or your drink of choice)

Sheraton Gateway Suites O'Hare 11th floor

Thursday, May 22nd 5:30 - 7:30pm