Web Programming Step by Step, 2nd Edition

Lecture 21: Web Services

Reading: none

Except where otherwise noted, the contents of this document are Copyright 2012 Marty Stepp, Jessica Miller, and Victoria Kirst. All rights reserved. Any redistribution, reproduction, transmission, or storage of part or all of the contents in any form is prohibited without the author's expressed written permission.

Valid HTML5 Valid CSS

What is a web service?

web service: software functionality that can be invoked through the internet using common protocols

Setting content type with header

header("Content-type: type/subtype");
header("Content-type: text/plain");
print "This output will appear as plain text now!\n";

Recall: Content ("MIME") types

MIME type related file extension
text/plain.txt
text/html.html, .htm, ...
text/xml.xml
application/json.json
text/css.css
text/javascript.js
image/gif.gif

Example: Exponent web service

Exercise: Baby name web service

What about errors?

Reporting errors

Using headers for HTTP error codes

header("HTTP/1.1  code  description");
if ($_GET["foo"] != "bar") {
	// I am not happy with the value of foo; this is an error
	header("HTTP/1.1 400 Invalid Request");
	die("An HTTP error 400 (invalid request) occurred.");
}
if (!file_exists($input_file_path)) {
	header("HTTP/1.1 404 File Not Found");
	die("HTTP error 404 occurred: File not found ($input_file_path)");
}

Checking for a mandatory query parameter

function get_query_param($name) {
	if (!isset($_GET[$name])) {
		header("HTTP/1.1 400 Invalid Request");
		die("HTTP/1.1 400 Invalid Request: missing required parameter '$name'");
	}
	if ($_GET[$name] == "") {
		header("HTTP/1.1 400 Invalid Request");
		die("HTTP/1.1 400 Invalid Request: parameter '$name' must be non-empty");
	}
	return $_GET[$name];
}

The $_SERVER superglobal array

index description example
$_SERVER["SERVER_NAME"] name of this web server "webster.cs.washington.edu"
$_SERVER["SERVER_ADDR"] IP address of web server "128.208.179.154"
$_SERVER["REMOTE_HOST"] user's domain name "hsd1.wa.comcast.net"
$_SERVER["REMOTE_ADDR"] user's IP address "57.170.55.93"
$_SERVER["HTTP_USER_AGENT"] user's web browser "Mozilla/5.0 (Windows; ..."
$_SERVER["HTTP_REFERER"] where user was before this page "http://www.google.com/"
$_SERVER["REQUEST_METHOD"] HTTP method used to contact server "GET" or "POST"

GET or POST?

if ($_SERVER["REQUEST_METHOD"] == "GET") {
	// process a GET request
	...
} elseif ($_SERVER["REQUEST_METHOD"] == "POST") {
	// process a POST request
	...
}

Emitting partial-page HTML data

// suppose my web service accepts a "type" query parameter ...
<?php if ($_GET["type"] == "html") { ?>
	<ul>
		<?php foreach ($students as $kid) { ?>
			<li> <?= $kid ?> </li>
		<?php } ?>
	</ul>
<?php } ?>

Exercise: Baby name web service XML

Emitting XML data manually

...
header("Content-type: text/xml");
print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
print "<books>\n";
foreach ($books as $book) {
	print "  <book title=\"{$book['title']}\" author=\"{$book['author']}\" />\n";
}
print "</books>\n";

PHP's XML DOM: DOMDocument

The PHP DOMDocument class represents an XML document. It has these methods:

createElement(tag) create a new element node to add to the document
createTextNode(text) create a new text node to add to the document
getElementById(id),
getElementsByTagName(tag)
search for elements in the document
load(filename),
loadXML(string)
read XML data from a file on disk or from a string
save(filename),
saveXML()
write XML data to a file on disk or returns it as a string
validate() return whether the current document consists of valid XML data

PHP's XML DOM: DOMElement

The PHP DOMElement class represents each DOM element. It has these fields/methods:

tagName, nodeValue node's name (tag) and value (text)
parentNode, childNodes,
firstChild, lastChild,
previousSibling, nextSibling
references to nearby nodes
appendChild(DOMNode),
insertBefore(newNode, oldNode),
removeChild(DOMNode)
manipulate this node's list of children
getElementsByTagName(tag) search for descendent elements within this element
getAttribute(name),
setAttribute(name, value),
removeAttribute(name)
get/set the value of an attribute on this tag

PHP XML DOM example

...
$xmldoc = new DOMDocument();                          // <?xml version="1.0"?>
$books_tag = $xmldoc->createElement("books");
$xmldoc->appendChild($books_tag);                     // <books>
foreach ($books as $book) {                                  
	$book_tag = $xmldoc->createElement("book");         //   <book
	$book_tag->setAttribute("title", $book["title"]);   //    title="Harry Potter" />
	$book_tag->setAttribute("author", $book["author"]); //    author="J.K. Rowling" />
	$books_tag->appendChild($book_tag);                      
}                                                     // </books>
header("Content-type: text/xml");
print $xmldoc->saveXML();

Exercise solution: Baby name web service XML

// takes a line of rankings and produces XML in the specified format
// example:  Aaron m 147 193 187 199 250 237 230 178 52 34 34 41 55
function generate_xml($line, $name, $gender) {
	$xmldom = new DOMDocument();
	$baby_tag = $xmldom->createElement("baby");     // <baby>
	$baby_tag->setAttribute("name", $name);
	$baby_tag->setAttribute("gender", $gender);
	
	$year = 1890;
	$tokens = explode(" ", $line);
	for ($i = 2; $i < count($tokens); $i++) {
		$rank_tag = $xmldom->createElement("rank");   // <rank>
		$rank_tag->setAttribute("year", $year);
		$rank_tag->appendChild($xmldom->createTextNode($tokens[$i]));
		$baby_tag->appendChild($rank_tag);
		$year += 10;
	}
	
	$xmldom->appendChild($baby_tag);
	return $xmldom;
}

Exercise: Baby name web service JSON

Emitting JSON data manually

...
header("Content-type: application/json");
print "{\n";
print "  \"books\": [\n";
foreach ($books as $book) {
	print "  {\"author\": \"{$book['author']}\", \"title\": \"{$book['title']}\"}\n";
}
print "\n";

PHP's JSON functions

PHP includes the following global functions for interacting with JSON data:

json_decode(string) parses the given JSON data string and returns an equivalent associative array object (like JSON.parse in JavaScript)
json_encode(object) returns JSON equivalent for the given object or array or value (like JSON.stringify in JavaScript)

PHP JSON example

<?php
$data = array(
	"library" => "Odegaard",
	"category" => "fantasy",
	"year" => 2012,
	"books" => array(
		array("title" => "Harry Potter", "author" => "J.K. Rowling"),
		array("title" => "The Hobbit", "author" => "J.R.R. Tolkien"),
		array("title" => "Game of Thrones", "author" => "George R. R. Martin"),
		array("title" => "Dragons of Krynn", "author" => "Margaret Weis"),
	)
);

header("Content-type: application/json");
print json_encode($data);
?>

PHP JSON example - output

{
	"library": "Odegaard",
	"category": "fantasy",
	"year": 2012,
	"books": [
		{"title": "Harry Potter", "author": "J.K. Rowling"},
		{"title": "The Hobbit", "author": "J.R.R. Tolkien"},
		{"title": "Game of Thrones", "author": "George R. R. Martin"},
		{"title": "Dragons of Krynn", "author": "Margaret Weis"},
	]
}

For reference: Provided web services code