by Enrico Zimuel - Zend Technologies Ltd.
28 August - Rovinj (Croatia)
Enrico Zimuel (@ezimuel), developer since 1996. Senior Software Engineer in the R&D department of Zend Technologies since 2008. Research programmer at the Informatics Institute of Amsterdam University in 2006. Open source contributor, core team of Apigility and Zend Framework. TEDx and international speaker about computer programming. Co-founder of PHP User Group Torino (Italy).
API stands for "Application Programming Interface" and as a term, specifies how software should interact.
In this worskhop we are interested in Web APIs, those delivered over HyperText Transfer Protocol (HTTP).
REpresentational State Transfer (REST) is an architecture designed around the HTTP specification.
REST leverages HTTP's strengths, and builds on:
Talking about REST, the Richardson Maturity Model is often used to describe the concerns necessary when implementing a well-designed REST API
The usage of HTTP as communication layer
A format for data representation (e.g. JSON)
Basically a Remote Procedure Call (RPC)
URIs as unique identifiers for resources
For instance, the resource User can be identified by
http://domain/api/user[/:user_id]
where user_id is an optional parameter
Usage of HTTP verbs for operations on resources
CRUD | HTTP verbs |
CREATE | POST |
READ | GET |
UPDATE | PUT, PATCH* |
DELETE | DELETE |
* partial update
Linking between resources to indicate relationships (hypermedia)
GET /api/user/ezimuel
{
"_links": {
"self": {
"href": "http://domain/api/user/ezimuel"
},
"contacts": [
{ "href": "http://domain/api/user/mwop" },
{ "href": "http://domain/api/user/zeevs" }
]
},
"id": "ezimuel",
"name": "Enrico Zimuel"
}
JSON-HAL format
Scalable architecture
Very easy to consume
Reduce client/server coupling
Discoverability
header('Content-Type: application/json');
echo json_encode([
'id' => 'ezimuel',
'name' => 'Enrico Zimuel'
]);
Quite simple, right?
No! What about error handling, hypermedia, data validation, content negotiation, versioning, etc?
GET /api/user/ezimuel
{
"_links": {
"self": {
"href": "http://domain/api/user/ezimuel"
}
}
"id": "ezimuel",
"name": "Enrico Zimuel"
}
{
"_links": {
"self": {
"href": "http://domain/api/user/ezimuel"
}
}
"id": "ezimuel",
"name": "Enrico Zimuel",
"_embedded": {
"contacts": [
{
"_links": {
"self": {
"href": "http://domain/api/user/mwop"
}
},
"id": "mwop",
"name": "Matthew Weier O'Phinney"
},
{
"_links": {
"self": {
"href": "http://domain/api/user/zeevs"
}
},
"id": "zeevs",
"name": "Zeev Suraski"
}
]
}
}
{
"_links": {
"self": {
"href": "http://domain/api/user?page=3"
},
"first": {
"href": "http://domain/api/user"
},
"prev": {
"href": "http://domain/api/user?page=2"
},
"next": {
"href": "http://domain/api/user?page=4"
},
"last": {
"href": "http://domain/api/user?page=133"
}
}
"count": 3,
"total": 498,
"_embedded": {
"users": [
{
"_links": {
"self": {
"href": "http://domain/api/user/mwop"
}
},
"id": "mwop",
"name": "Matthew Weier O'Phinney"
},
{
"_links": {
"self": {
"href": "http://domain/api/user/mac_nibblet"
}
},
"id": "mac_nibblet",
"name": "Antoine Hedgecock"
},
{
"_links": {
"self": {
"href": "http://domain/api/user/spiffyjr"
}
},
"id": "spiffyjr",
"name": "Kyle Spraggs"
}
]
}
}
Content-Type: application/problem+json
{
"detail": "The GET method has not been defined for individual",
"status": 405,
"title": "Method Not Allowed",
"type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"
}
Accept: application/hal+json, application/json
Agility uses two approaches:
v1
/userv1
+json Apigility supports three different authentication systems: HTTP Basic, HTTP Digest, and OAuth2
Start the environment
(netgen/summercamp-2015):
172.21.12.10 apigility.phpsc
All the exercise are on github:
https://github.com/ezimuel/php-summercamp-apigility
Four exercises with solutions in branches: exercise/1, exercise/2, exercise/3, and exercise/4
In your environment:
/speaker[/:speaker_id]
/talk[/:talk_id]
CREATE TABLE speakers (
id INTEGER PRIMARY KEY,
name VARCHAR(80) NOT NULL,
title VARCHAR(80) NOT NULL,
company VARCHAR(80) NOT NULL,
url_company VARCHAR(255),
twitter VARCHAR(80)
);
CREATE TABLE talks (
id INTEGER PRIMARY KEY,
title TEXT,
abstract TEXT,
day TEXT,
start_time TEXT,
end_time TEXT
);
CREATE TABLE talks_speakers (
talk_id INTEGER NOT NULL,
speaker_id INTEGER NOT NULL
);
The Data Mapper is a class that interacts with the data model
It's consumed by REST Resource to return Entities/Collection
Can be injected in the Resource using ResourceFactory
Apigility offers the management of DBs using adapters
Support for PDO, MySQL, Oci8, IbmDb2, PgSQL, SqlSrv
Use the Zend\Db\Adapter component of ZF2
In your environment:
* use the Zend\Validator\Date with the options "format" to "Y-m-d"
In your environment:
Using the _embedded field format, add the following:
* Add a speakers field in TalkEntity to return a SpeakerCollection
In your environment:
More information on apigility.org
Contact me: enrico [at] zend.com
Rate this talk https://joind.in/15133
This work is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
I used reveal.js to make this presentation.