+ All Categories
Home > Documents > rob richards-web services

rob richards-web services

Date post: 13-Nov-2014
Category:
Upload: dan-previte
View: 824 times
Download: 5 times
Share this document with a friend
Popular Tags:
124
Working With Web Services Rob Richards May 20, 2008 http://xri.net/=rob.richards
Transcript
Page 1: rob richards-web services

Working With Web ServicesRob Richards

May 20, 2008

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

Page 2: rob richards-web services

• GET / POST

• Restful

• REST

• XML-RPC

• JSON-RPC

• SOAP

Common Types Of Services

2

Page 3: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

JSON-RPC Response

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

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

18

Page 19: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

Deciding Upon A Service

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

What To Use?

?22

Page 23: rob richards-web services

Intended Audience

• Exposing To The Masses

• Internal Developers

• Business Partners

• Multiple Audiences

23

Page 24: rob richards-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: rob richards-web services

What Is The Purpose?

• Reduce system maintenance?

• Expose existing logic as services?

• Expose logic from legacy systems?

• Aggregate functionality?

25

Page 26: rob richards-web services

Any Curveballs?

• Two-phase commits

• Asynchronous Messaging

• Legacy System Protocols

• Multi-System Involvement

26

Page 27: rob richards-web services

Let’s Get Our Hands Dirty!

Page 28: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

Google Calendar

35

Page 36: rob richards-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: rob richards-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: rob richards-web services

Google Calendar Our Login

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

38

Page 39: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

Now What???

No Error, But No New Entry

44

Page 45: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

Our Calendar

49

Page 50: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

Updated Calendar

55

Page 56: rob richards-web services

Working With SOAP

Page 57: rob richards-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: rob richards-web services

Working With soapUI

58

Page 59: rob richards-web services

Eclipse WSDL Editing

59

Page 60: rob richards-web services

Eclipse WSDL Editing

60

Page 61: rob richards-web services

Eclipse XML Schema Editing

61

Page 62: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

When Things Go Wrong...

Fault: ForbiddenCode: HTTP

71

Page 72: rob richards-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: rob richards-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: rob richards-web services

Let’s Try soapUI

74

Page 75: rob richards-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: rob richards-web services

Server Sided SOAP

Page 77: rob richards-web services

DISABLE WSDL CACHINGWHEN DEVELOPING!

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

Disable That Cache

77

Page 78: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

Creating Our Service

Page 84: rob richards-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: rob richards-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: rob richards-web services

Create The WSDL

86

Page 87: rob richards-web services

Creating The WSDL

87

Page 88: rob richards-web services

Creating The WSDL

88

Page 89: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

Service Component Architecture (SCA)

Page 95: rob richards-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: rob richards-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: rob richards-web services

SCA Components

97

BusinessLogic

Annotations

Binding Types

Data Types

InterfaceDescription

SOAP Request

JSON Request

REST Request

Developer’sResponsibility

Page 98: rob richards-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: rob richards-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: rob richards-web services

Complex Types

include "SCA/SCA.php";

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

100

Page 101: rob richards-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: rob richards-web services

Creating The XML Schema

102

Page 103: rob richards-web services

Creating The XML Schema

103

Page 104: rob richards-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: rob richards-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: rob richards-web services

Referencing Components

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

106

Page 107: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

WSO2 Web Services Framework for PHP

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

Page 111: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-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: rob richards-web services

Working With Web Services

Rob Richards

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

Page 124: rob richards-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


Recommended