Develop and design RESTful web API in PHP using Apigility

by Enrico Zimuel - Twitter: @ezimuel
Senior Sofware Engineer, Zend Technologies Ltd


28th March - Rome (Italy)

About me

Professional Developer since 1996. Senior Software Engineer at Zend Technologies, since 2008. Research in computer science at the Informatics Institute of Amsterdam University. Open source contributor and co-author of Apigility and Zend Framework. Co-author of the Italian books PHP Best Practices and Javascript Best Practices. Co-founder of PUG Torino (Italy).

API

API stands for "Application Programming Interface" and as a term, specifies how software should interact.

When we refer to APIs today, we are referring more specifically to web APIs, those delivered over HyperText Transfer Protocol (HTTP).

REST

REpresentational State Transfer (REST) is an architecture designed around the HTTP specification.

Glory of REST

Talking about REST, the Richardson Maturity Model is often used to describe the concerns necessary when implementing a well-designed REST API

REST: Level 0

The usage of HTTP as communication layer

A format for data representation (e.g. JSON)

Basically a Remote Procedure Call (RPC)

REST: Level 1

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

REST: Level 2

Usage of HTTP verbs for operations on resources

CRUD HTTP verbs
CREATE POST
READ GET
UPDATE PUT, PATCH*
DELETE DELETE

* partial update

REST: Level 3

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

HATEOAS

Hypermedia As The Engine Of Application State

Advantages of REST

Scalable architecture

Very easy to consume

Reduce client/server coupling

Discoverability

REST in PHP


$data = array(
	'id'   => 'ezimuel',
	'name' => 'Enrico Zimuel'
);
header('Content-Type: application/json');
echo json_encode($data);

Quite simple, right?

No! What about error handling, hypermedia, data validation, content negotiation, versioning, etc?

RESTful in practice?

Can be difficult, especially at the beginning

Issue

  • Which representation format to use?
  • How to handle error messages?
  • How to support authentication?
  • How to support hypermedia?
  • How to generate API documentation?

Possible answers

  • Which representation format to use? JSON
  • How to handle error messages? application/problem+json
  • How to support authentication? OAuth2
  • How to support hypermedia? JSON HAL
  • How to generate API documentation? HTML, Swagger

Apigility

Main features

  • RPC and REST
  • JSON (HAL) as default format
  • Error handling (API Problem)
  • Content negotiation
  • Versioning (via URI and Accept header)
  • Filtering and validation
  • Authentication (HTTP Basic/Digest, OAuth2)
  • Interactive documentation (HTML, Swagger)

JSON HAL

  • JSON Hypertext Application Language, is a RFC draft proposal (draft-kelly-json-hal-06)
  • Example:
    
    GET /api/user/ezimuel
    
    {
        "_links": {
            "self": {
                "href": "http://domain/api/user/ezimuel"
            }
        }
        "id": "ezimuel",
        "name": "Enrico Zimuel"
    }
    

_embedded


{
    "_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"
            }
        ]
    }
}

Collections


{
    "_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"
            }
        ]
    }
}

API Problem

  • API Problem is a RFC draft proposal (draft-ietf-appsawg-http-problem-00)
  • Example:
    
    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"
    }
    

Content negotiation

  • Content negotiation is a mechanism defined in the HTTP specification that makes it possible to serve different versions of a document at the same URI.
  • Example:
    
    Accept: application/hal+json, application/json
    

API Versioning

Agility uses two approaches:

  • In the URL, e.g. /api/v1/user
  • By Accept header, e.g. Accept:application/vnd.example.v1+json

Authentication

Apigility supports three different authentication systems: HTTP Basic, HTTP Digest, and OAuth2

Installation

Super easy, just one command:


curl -sS https://apigility.org/install | php

Or, if you don't have CURL installed:


php -r "readfile('https://apigility.org/install');" | php

Apigility UI

Open the browser to http://localhost:8888

Preview of the new UI of Apigility 1.1

Some resource

Thanks!

Rate this talk: https://joind.in/14149

More information on apigility.org

Contact me: enrico [at] zend.com

Follow me: @ezimuel



Creative Commons License
This work is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
I used reveal.js to make this presentation.