rob richards-web services

Preview:

Citation preview

Working With Web ServicesRob Richards

May 20, 2008

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

• GET / POST

• Restful

• REST

• XML-RPC

• JSON-RPC

• SOAP

Common Types Of Services

2

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

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

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

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

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

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

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

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

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

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

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

<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

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

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

JSON-RPC Response

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

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

18

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

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>jsmith123@hotmail.com</email> </to> <from> <email>jjohnson64@yahoo.com</email> </from> <simplebody> <text>this is a test</text> </simplebody> <subject>test</subject> </message> </m:SendMessage> </SOAP-ENV:Body></SOAP-ENV:Envelope>

20

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

Deciding Upon A Service

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

What To Use?

?22

Intended Audience

• Exposing To The Masses

• Internal Developers

• Business Partners

• Multiple Audiences

23

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

What Is The Purpose?

• Reduce system maintenance?

• Expose existing logic as services?

• Expose logic from legacy systems?

• Aggregate functionality?

25

Any Curveballs?

• Two-phase commits

• Asynchronous Messaging

• Legacy System Protocols

• Multi-System Involvement

26

Let’s Get Our Hands Dirty!

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

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

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

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

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

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

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

Google Calendar

35

Google Calendar Login

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

$params = array('Email'=>'rrichards@cdatazone.org', '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

Google Calendar Login Using ext/http

$url = 'https://www.google.com/accounts/ClientLogin';$params = array('Email'=>'rrichards@cdatazone.org', '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

Google Calendar Our Login

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

38

Get Auth Token

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

39

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

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

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

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

Now What???

No Error, But No New Entry

44

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

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

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

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="cdatazone.org@gmail.com"/> <gd:where valueString="The Bar"/></entry>

48

Our Calendar

49

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

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="ns4d6037c1kvrm4i5ena2oo9h4@google.com"/> <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="cdatazone.org@gmail.com"/> <gd:where valueString="The Bar"/></entry>

51

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

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="ns4d6037c1kvrm4i5ena2oo9h4@google.com"/> <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="cdatazone.org@gmail.com"/> <gd:where valueString="11th Floor"/></entry>

53

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

Updated Calendar

55

Working With SOAP

• 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

Working With soapUI

58

Eclipse WSDL Editing

59

Eclipse WSDL Editing

60

Eclipse XML Schema Editing

61

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

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

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

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

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

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

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

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

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

When Things Go Wrong...

Fault: ForbiddenCode: HTTP

71

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

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

Let’s Try soapUI

74

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

Server Sided SOAP

DISABLE WSDL CACHINGWHEN DEVELOPING!

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

Disable That Cache

77

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

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

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

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

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

Creating Our Service

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

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

Create The WSDL

86

Creating The WSDL

87

Creating The WSDL

88

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

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

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

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

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

Service Component Architecture (SCA)

• 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

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

SCA Components

97

BusinessLogic

Annotations

Binding Types

Data Types

InterfaceDescription

SOAP Request

JSON Request

REST Request

Developer’sResponsibility

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

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

Complex Types

include "SCA/SCA.php";

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

100

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

Creating The XML Schema

102

Creating The XML Schema

103

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

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

Referencing Components

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

106

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

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

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

WSO2 Web Services Framework for PHP

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

• 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

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

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

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

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

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

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

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

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

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

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

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

Working With Web Services

Rob Richards

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

We Are Hiring PHP & AJAX Developers Contact us: jobs@mashery.com

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

Recommended