
The key to victory is discipline,
and that means a well made bed.

Not sure if trolling or just “technically correct”

This chronological wang-dang-doodle
could destroy the very matrix of reality.

/api) and one METHOD (POST)
$_POST) you get back some data
GETPOST request to /api with $_POST['action'] set to getLecturers and get back a list of lecturers as the actual content
{
"lecturers":
[
{
"id": 1,
"name": "Davy De Winne"
},
{
"id": 2,
"name": "Bramus Van Damme"
}
]
}

/product/products/product/1234/products/1234/photos/product/1234/products/1234/photos/photos/product/1234/5678/products/1234/photos/5678/things/animals/dogs/beagles/search?course=WMD/convert?from=EUR&to=USD&amount=100//movies/movies/{id}/movies/{id}/photos/actors/actors/{id}/actors/{id}/movies/about/contactPOST request to /api/lecturers and get back a list of lecturers as the actual content
{
"lecturers":
[
{
"id": 1,
"name": "Davy De Winne"
},
{
"id": 2,
"name": "Bramus Van Damme"
}
]
}
api.twitter.com/v1/… is wrong)
?filter=foo&sort=asc?fields=firstname,lastname,agelimit and offset URL params
?limit=10&offset=<max_id>offset, opt for id-constraint based on sorting method; this avoids doubles when paginating over a frequently updated result set.
POST = Create = INSERTGET = Read = SELECTPUT = Update = UPDATEDELETE = Delete = DELETEPOST /products (data via $_POST)GET /products or GET /products/1234PUT /products/1234 (data via “$_PUT”)DELETE /products/1234401 — Not Authorized (e.g. No API Key given)405 — Method Not Allowed (e.g. wrong verb for resource)500 — Internal Server Error (Developer screwed up ;))GET (SQL SELECT)
200 — OK (requested data sent via response body)404 — Not Found (resource not found, not “API not found”)POST (SQL INSERT)
201 — Created (=OK)400 — Bad Request (Missing Parameters)PUT (SQL UPDATE)
200 — OK (requested data sent via response body)400 — Bad Request (Missing Parameters)404 — Not FoundDELETE (SQL DELETE)
204 — No Content (=OK — Note: no response body sent!)404 — Not Found$.ajax().error() in jQuery!GET request to /api/lecturers and get back an HTTP 200 status code and a list of lecturers as the content
{
"lecturers":
[
{
"id": 1,
"name": "Davy De Winne"
},
{
"id": 2,
"name": "Bramus Van Damme"
}
]
}
POST request to /api/lecturers with some data in $_POST to insert a new lecturer
201 — Created if all OK400 — Bad Request if parameters are missingPUT request to /api/lecturers/2 with some data in $_PUT to update a lecturer
200 — OK if all OK400 — Bad Request if parameters are missing404 — Not Found if the lecturer does not exist
The simultaneous presentation of information and controls such that the information becomes the affordance through which the user obtains choices and selects actions⚑
application/atom+xmlapplication/vnd.ikdoeict.whateveraccept header which
Accept: application/collection+jsonAccept: application/xml; q=0.8, application/jsonAccept: application/vnd.ikdoeict.whatever-v2+jsonAccept: application/collection+json;v=2application/json (Sorry Roy, gotta pave the cowpaths)
status and content objectlinks array holding the links
rel and href property
rel values are based on RFC5988
self, up, index, next, prev, ...photos)GET request to /lecturers and get back a custom JSON response with HTTP status code 200 containing a list of lecturers (with resource links) as the response content
{
"status":
{
"code": 200,
"text": "OK"
},
"content":
{
"size": 2,
"lecturers":
[
{
"id": 1,
"name": "Davy De Winne",
"links": [
{
"rel": "self",
"href": "/users/1"
}
]
},
{
"id": 2,
"name": "Bramus Van Damme",
"links": [
{
"rel": "self",
"href": "/users/2"
}
]
}
]
}
}
application/json — It cuts the mustard

Hey, look! I found a robot fossil!
GET api.twitter.com/1/statuses/show/id.formatshow included in URLid not a child of statusesGET api.twitter.com/statuses/{id}POST api.twitter.com/1/statuses/update/id.formatupdate included in URLPOST api.twitter.com/users/{id}/statusesPOST api.twitter.com/1/statuses/destroy/id.formatdestroy included in URLDELETE api.twitter.com/users/{id}/statuses/{id}GET api.twitter.com/1/statuses/retweets/id.formatGET api.twitter.com/statuses/{id}/retweets

Would it cheer you up if I punch Fry in the groin?
Cause I'll do it, regardless.
index.php
index.php in such a way that it decides what to do based on the URL (found in $_SERVER['REQUEST_URI'])
mod_rewrite Apache Module
.htaccess in your root to redirect requests to non-existing files to index.php
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ˆ /index.php [L]
</IfModule>
web.config in your root to redirect requests to non-existing files to index.php
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Main Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
index.php by default
index.php to force non-404 requests route to the correct file
<?php
$filename = __DIR__ . preg_replace('#(\?.*)$#', '', $_SERVER['REQUEST_URI']);
if (php_sapi_name() === 'cli-server' && is_file($filename)) {
return false;
}
// rest of your code hereGET request to /movies, show a list of moviesGET request to /movies/{id}, show the one specific moviePOST request to /movies, insert it$router = new Router();
$router->get('/', function() { … });
$router->get('/movies', function() { … });
$router->get('/movies/\d+', function() { … });
$router->post('/movies', function() { … });
$router->run();

Let's take a look at assets/07/examples/router/ →
match()
$router->match('GET|POST', 'pattern', function() { … });
$router->get('pattern', function() { … });
\d+, \w+, .*, or .+) will be converted to route variables which you pass into the handling function$router->get('/movies/\d+', function($movieId) {
echo 'Movie #' . $movieId . ' detail';
});
$router->get('/movies/\d+/photos/\d+', function($movieId, $photoId) {
echo 'Movie #' . $movieId . ' photo #' . $photoId);
});
$router->set404(function);$router->before('GET|POST', 'pattern', function() {
// ...
});
$router->before('GET|POST', '/admin/.*', function() {
if (!isset($_SESSION['userId'])) { … }
});
run function$router->run(function() { … });
Response class
$status and $content datamembers + mutators200<?php
namespace Ikdoeict\Rest;
class Response {
private $status, $content;
public function __construct() {
$this->setStatus(200);
$this->setContent('');
}
final public function setStatus($statusCode) {
$codes = array(
200 => 'OK',
// ... List of statuscode with status texts
);
$this->status = array(
'code' => $statusCode,
'text' => $codes[$statusCode]
);
header('HTTP/1.1 ' . $this->status['code'] . ' ' . $this->status['text']);
}
final public function setContent($content) {
$this->content = $content;
}
public function finish() {
$json = json_encode(
array(
'status' => $this->status,
'content' => $this->content
)
);
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');
echo $json;
exit();
}
}
// EOF
$_GET['callback'] to the finish functionpublic function finish($jsonp = null) {
$json = …
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
if ($jsonp) {
header('Content-type: application/javascript');
echo $jsonp . '(' . $json . ');';
} else {
header('Content-type: application/json');
echo $json;
}
exit();
}

Let's take a look at assets/07/examples/response/ →
<?php
$router = new Ikdoeict\Routing\Router();
$response = new Ikdoeict\Rest\Response();
// Override the standard router 404
$router->set404(function() use ($response) {
$response->setStatus('404');
$response->setContent('Invalid resource');
$response->finish();
});
// Define our routes
$router->get('', function() use ($response) {
$response->setContent('Welcome!');
});
// … (more routes here)
// Run the router
$router->run(function() use ($response) {
$response->finish(isset($_GET['callback']) ? $_GET['callback'] : null);
});
// EOF
$_PUT, you'll need to fake it<?php
//…
$router->put('/movies/\d+', function() {
// Fake $_PUT
$_PUT = array();
parse_str(file_get_contents('php://input'), $_PUT);
// …
});
//…

To the flying machine!
success and error functions
$.ajax({
url : 'http://api.myapp.tld/',
type: 'get|post|put|delete',
dataType : 'json',
data: 'foo=bar'
})
.success(function(data, textStatus, jqXHR) {
if (data) {
// All OK and data returned (200, 201)
} else {
// All OK but no data returned (e.g. 204 after a DELETE)
}
})
.error(function(jqXHR, textStatus, errorThrown) {
var data = jqXHR.responseText ? JSON.parse(jqXHR.responseText) : {};
// Got a 400 (params), 401, 404, 405 (method), 500, or 501 (not impl)
});
Who are those horrible orange creatures over there? — Grunka-Lunkas. — Tell them I hate them!
$router->before('GET|POST|PUT|DELETE', '.*', function() use ($response) {
$headers = apache_request_headers();
if(!isset($headers['X-Api-Key']) || !ApiDB::isValidApiKey($headers['X-Api-Key'])) {
$response->setStatus(401);
$response->setContent('Missing or invalid API Key.');
$response->finish();
}
});
X and all words must be ucfirst'd and separated with -
apache_request_headers() not always available (IIS)!
if (!function_exists('apache_request_headers')) {
eval('
function apache_request_headers() {
foreach($_SERVER as $key=>$value) {
if (substr($key,0,5)=="HTTP_") {
$key=str_replace(" ","-",ucwords(strtolower(str_replace("_"," ",substr($key,5)))));
$out[$key]=$value;
}
}
return $out;
}
');
}


client_id) for identification), asking if consumer app may access user data at a certain scope (read/write)redirect_uri with an authorization_codeauthorization_code, along with its API-Key (client_id) and secret key (client_secret)access_token and refresh_tokenaccess_token must passed with all calls made and is valid for a limited timeaccess_token has expired, the consumer app needs to do a call to the OAuth Prodider with the refresh_token to get a new pair access_token & refresh_token