Beruflich Dokumente
Kultur Dokumente
Lorna Mitchell
• PHP Consultant/Developer/Trainer
• API Specialist
• Twitter: @lornajane
• Site: http://lornajane.net
2
Agenda
• RPC Services
3
Theory and Introduction
What Is A Web Service?
5
Web Services and You
6
Architecture Using APIs
7
Let’s Begin
Building Blocks
• Framework module
• Component library
9
My First Web Service
• e.g. http://api.local
• Don’t forget to restart apache
• Add an entry to your hosts file
<VirtualHost *:80>
ServerName api.local
ServerAdmin admin@localhost
DocumentRoot /var/www/myapi/public
<Directory /var/www/myapi/public>
AllowOverride All
Order deny,allow
Allow from All
</Directory>
</VirtualHost>
api.vhost
10
My First Web Service
• e.g. /var/www/myapi/public/index.php
$data = array(
'format' => 'json',
'status' => 'live'
);
echo json_encode($data);
public/index.php
11
Consume Your Service
• curl http://api.local
• http://curl.haxx.se/
• http://bit.ly/esqBmz
12
JSON JavaScript Object Notation
13
Heartbeat Method
• No authentication
14
Delivering A Web Service
• Service
• Documentation
• Examples
• A help point
15
HTTP and Data Formats
HTTP
17
Status Codes
200 OK
302 Found
301 Moved
401 Not Authorised
403 Forbidden
404 Not Found
500 Internal Server Error
18
Working with Status Codes in PHP
$data = array(
'format' => 'json',
'status' => 'live'
);
echo json_encode($data);
19
HTTP Verbs
GET Read
POST Create
In REST, we use:
PUT Update
DELETE Delete
20
HTTP Headers
Useful headers:
21
Accept Header
• -H to add headers
22
Using the Accept Header
We can work out what format the user wanted to see from the Accept
header.
$data = array(
'status' => 'live',
'now' => time()
);
public/headers.php
23
Content-Type Header
public/headers.php
24
Handling XML Formats
• SimpleXML bit.ly/g1xpaP
• DOM bit.ly/e0XMzd
25
Adding XML to Our Service
$data = array(
'status' => 'live',
'now' => time()
);
header('Content-Type: text/xml');
echo $simplexml->asXML();
26
How to REALLY Handle Accept Headers
• http://arbitracker.org
• src/classes/request/parser.php
• Try this from curl, setting your own headers, and from your browser
27
Versions and Formats
• JSON
• XML
• HTML
• ?
28
Statelessness
29
Consuming Services from PHP
Consuming Your First Web Service
• bit.ly/h5dhyT
• Using Pecl_HTTP
• bit.ly/g4CfPw
31
Using File_Get_Contents
32
Using Curl
Look out for the CURLOPT_RETURNTRANSFER; without it, this will echo
the output
33
Using Pecl_HTTP
This is the most powerful and flexible, and can easily be installed from
http://pecl.php.net
$request = new HTTPRequest('http://api.local/', HTTP_METH_GET);
$request->send();
$response = $request->getResponseBody();
var_dump($response);
34
Service Types
Web Service Types
• RESTful
• XML-RPC
• JSON-RPC
• Soap
36
RPC Services
• A single endpoint
• Method names
• Method parameters
• A return value
37
Soap
• Not an acronym
38
Soap Example: Library Class
class Library {
public function thinkOfANumber() {
return 42;
}
39
Publishing a Soap Service
include('Library.php');
$server->handle();
/public/soap/index.php
40
Consuming a Soap Service
Over Soap:
$options = array('uri' => 'http://api.local',
'location' => 'http://api.local/soap');
$client = new SoapClient(NULL, $options);
$name = $client->thinkOfAName();
echo $name; // Arthur Dent
41
Pros and Cons of Soap
42
Pros and Cons of Soap
42
Pros and Cons of Soap
• When it doesn’t work, it’s horrid to debug (so I’ll show you how)
42
Pros and Cons of Soap
• When it doesn’t work, it’s horrid to debug (so I’ll show you how)
• WSDL is complicated!
42
Working with WSDLs
• If you do need to read one, start at the END and read upwards in
sections
43
Debugging Soap
• getLastRequest(), getLastRequestHeaders(),
getLastResponse(), getLastResponseHeaders() are then
available
• SoapUI (http://soapui.org)
44
Wireshark Demo
45
Extending Our Service
Consistency
• Important to retain
• Naming conventions
• Parameter validation rules
• Parameter order
47
The Action Parameter
/rpc/index.php
/rpc/actions.php
So try http://api.local/rpc/index.php?action=getSiteStatus
48
Small APIs
• Simple is maintainable
49
Adding an Action
To add a new action, create a new method for the Actions class, returning
an array to pass to the output handlers
public function addTwoNumbers($params) {
return array('result' => ($params['a'] + $params['b']));
}
/rpc/actions.php
/rpc/index.php
50
Access Control
• OAuth
51
RPC Service Example: Flickr
52
RPC vs REST
We’ve seen an RPC service, but what about REST? The two are quite
different
53
RESTful Web Service
REST
55
REST as a Religion
• The strict rules around REST sometimes fit badly around business
requirements
56
Making Our Service Restful
• http://api.local/rest/user
• http://api.local/rest/user/3
• http://api.local/rest/user/3/friends
A specific item is a resource; where you request a list, e.g. /user, this is
called a collection
57
All Requests to index.php
/public/rest/.htaccess
58
Routing Within Our App
So our routing depends on the URL and on the verb used, so our
controllers have a method per verb:
• GET /user
• Becomes UserController::GETAction()
// output appropriately
$view->render($data);
/public/rest/index.php
59
A Simple Controller
if(isset($parameters[2])) {
return $users[(int)$parameters[2]];
} else {
return $users;
}
}
}
/public/rest/controllers.php
60
Calling our Service
$ch = curl_init('http://api.local/rest/users');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
print_r(json_decode($result, true));
/public/rest-test.php
61
Extending our Service
if(isset($parameters[2])) {
if(isset($parameters[3]) && $parameters[3] == 'friends') {
return $friends[(int)$parameters[2]];
} else {
return $users[(int)$parameters[2]];
}
} else {
return $users;
}
}
}
/public/rest/controllers.php
62
Hypermedia
63
Creating New Records
// redirect user
header('HTTP/1.1 201 Created');
header('Location: http://api.local/rest/users/5');
return $new_user;
}
/public/rest/controllers.php
64
Incoming POST/PUT Data
$verb = $_SERVER['REQUEST_METHOD'];
$data = array();
switch($verb) {
case 'GET':
parse_str($_SERVER['QUERY_STRING'], $data);
break;
case 'POST':
case 'PUT':
// incoming JSON data, it's an array
$data = json_decode(file_get_contents('php://input'), true);
break;
/public/rest/index.php
65
POSTing JSON Data from PHP
Adding some appropriate data handling and headers to the curl call:
$data = array("name" => "Hagrid", "age" => "36");
$data_string = json_encode($data);
$ch = curl_init('http://api.local/rest/users');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string))
);
$result = curl_exec($ch);
print_r(json_decode($result, true));
/public/rest-test.php
66
Appropriate Status Codes for REST
• GET
• POST
• PUT
• DELETE
• Be consistent
• Be accurate
68
Delivering Services
Technical Aspects
• Source control
• Unit/Integration testing
• Automated deployment
• Monitoring
70
User Aspects
• Respond to questions
71
Questions?
Resources
73
Thanks
• http://joind.in/talk/view/3461
• http://lornajane.net
74