Date post: | 13-Nov-2014 |
Category: |
Documents |
Upload: | dan-previte |
View: | 824 times |
Download: | 5 times |
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
REST Delete Entry
<link rel="edit" type="application/atom+xml" href="http://www.google.com/calendar/feeds/default/private/full/asdc/63346405484"/>
HTTP DELETE to edit URL
http://www.google.com/calendar/feeds/default/private/full/asdc/63346405484
Successful deletion returns status 200
12
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 & 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>[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
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 & 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'=>'[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
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
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="[email protected]"/> <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="[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
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="[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
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><DOCUMENT>
<TYPE>NEWS</TYPE>
<SOURCEURL> http://biz.yahoo.com/rb/030905/airlines_damages_1.html </SOURCEURL>
...</param1>
<param2><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: [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