
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, but use all HTTP verbs
POST, GET, PUT, PATCH, DELETE, …404, 500, …POST = Create = INSERTGET = Read = SELECTPUT = Update = UPDATEPATCH = Update = UPDATEDELETE = Delete = DELETEPOST /products (data via $_POST)GET /products or GET /products/1234PUT /products/1234 (data via “$_PUT”)DELETE /products/1234PUT = replace a resource entirely
PATCH = partially replace a resource
ThePATCHmethod applies a delta (diff) rather than replacing the entire resource. The request entity toPATCHis of a different content-type that the resource that is being modified. Instead of being an entire resource representation, it is a resource that describes changes to apply on a resource.
Source: Please don't patch like an idiot
400 — Bad Request (e.g. Request Body is malformed / not parseable)401 — Not Authorized (e.g. No API Key given)405 — Method Not Allowed (e.g. wrong verb for resource)415 — Unsupported Media Type422 — Unprocessable Entity (Validation Errors)429 — Too Many Requests (Rate Limiting)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/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 statuses.format at the end)GET api.twitter.com/statuses/{id}POST api.twitter.com/1/statuses/update.formatupdate included in URL.format at the end)POST api.twitter.com/statuses

Would it cheer you up if I punch Fry in the groin?
Cause I'll do it, regardless.
GET 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();
Response class
$status and $content datamembers + mutators200\Symfony\Component\HttpFoundation\Response!⚑
getContent() to transform the content to the format we need
Content-Type: application/json header$_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