1. RESTful Modules in ZF2
Walter Dal Mut – walter.dalmut@gmail.com - @walterdalmut
https://github.com/wdalmut
@walterdalmut - www.corley.it - www.upcloo.com
2. About Me
• Walter Dal Mut (@walterdalmut)
• Electronic Engineer
• Polytechnic University of Turin
• Startupper
• Corley S.r.l. – www.corley.it
• Cloud Computing Services
• UpCloo Ltd. – www.upcloo.com
• Semantic Most Related Links service
@walterdalmut - www.corley.it - www.upcloo.com
4. RESTful? What it means in few words…
• Representational State Transfer (REST)
• Architecture is based on Client-Server
• Clients initiate requests to servers; servers process requests and return
appropriate responses
• Flexible, the application must know messages format
• XML
• JSON
• Etc.
@walterdalmut - www.corley.it - www.upcloo.com
5. RESTful services are resource centric
• Resources (sources of specific information)
• Each resource is referenced with a global identifier (URI, etc.)
• Any number of connectors can mediate the request
• Clients
• Servers
• Caches
• Tunnels
@walterdalmut - www.corley.it - www.upcloo.com
6. REST Constraints
• Client-Server
• A uniform interface separates clients from servers.
• Stateless
• The client–server communication is further constrained by no client context being
stored on the server between requests.
• Cacheable
• Clients can cache responses
• Layered System
• Intermediary servers may improve system scalability by enabling load-balancing and
by providing shared caches. They may also enforce security policies.
• Uniform interface
• Simplify and decouples the architecture
@walterdalmut - www.corley.it - www.upcloo.com
7. Several types of RESTful services
• URI Templates
• http://rest.domain.tld/order/{orderID}
• One of the major uses for URI templates is as human- and machine-readable
documentation.
• URI Tunneling
• http://rest.domain.tld/PlaceOrder?pizza=margherita&type=classic
• Rest.domain.tld service
• PlaceOrder method
• Pizza=margherita&type=classic arguments
• POX – Plain Old XML over HTTP
• Similar to URI Tunneling but information will be sent as XML document in the
HTTP request from the customer.
@walterdalmut - www.corley.it - www.upcloo.com
8. POX – Plain Old XML over HTTP
example
POST /PlaceOrder HTTP/1.1
Content-Type: application/xml
Client application Application domain
<Order>
<Pizza>
<Name>margherita</Name>
<Type>classic</Type>
</Pizza>
</Order>
HTTP/1.1 200 OK
<OrderConfirmation>
<OrderID>1345</OrderID>
</OrderConfirmation>
@walterdalmut - www.corley.it - www.upcloo.com
9. CRUD Webservices
• CRUD what it means?
• Create, Read, Update and Delete
• Patterns for manipulating resources across the network
• Extended usage of HTTP verbs
• GET
• POST
• PUT
• DELETE
• Using HTTP as an application protocol instead of a transport protocol
• Web is really a big framework for building distributed systems.
@walterdalmut - www.corley.it - www.upcloo.com
10. HTTP verbs in CRUD services
• Get Read Operation
• Used to retrive resource details
• http://rest.service.tld/order/10
• Post Create Operation
• Used to create new resources
• Put Update Operation
• Used to update existing resources
• Delete Delete Operation
• Used to delete existing resources
POST/PUT can be exchanged and sometimes PUT/DELETE can be excluded to
enable javascript integration (PUT/DELETE not supported browser side
[HTTP_X_HTTP_METHOD_OVERRIDE parameter])
@walterdalmut - www.corley.it - www.upcloo.com
11. CRUD Summary
Verb URI or Template Use
POST /order Create a new order, and upon success, receive a Location header specifying the
new order’s URI.
GET /order/{id} Request the current state of the order specified by the
URI.
PUT /order/{id} Update an order at the given URI with new information,
providing the full representation.
DELETE /order/{id} Logically remove the order identified by the given URI.
@walterdalmut - www.corley.it - www.upcloo.com
12. Status code definition (short list)
• 2xx (Positives)
• 200 OK – The request has succeeded.
• 201 Created – The server accept the request and it has created the resource.
• 202 Accepted – The request has been accepted for processing, but the processing has not been completed.
• 4xx (Client Errors)
• 400 Bad Request – The request could not be understood by the server due to malformed syntax.
• 401 Unauthorized – The request requires user authentication.
• 403 Forbidden – The server understood the request, but is refusing to fulfill it.
• 404 Not found – The server has not found anything matching the Request-URI.
• 405 Method not allowed – The method specified in the Request-Line is not allowed for the resource identified
by the Request-URI.
• 5xx (Server Errors)
• 500 Internal Server Error – The server encountered an unexpected condition which prevented it from fulfilling
the request.
• 501 Not implemented – The server does not support the functionality required to fulfill the request.
• 503 Service unavailable – The server is currently unable to handle the request due to a temporary overloading
or maintenance of the server.
@walterdalmut - www.corley.it - www.upcloo.com
13. RESTful module idea
• Router
• Wire requests to RESTful controllers
• RESTful Controllers
requests Router • Uses HTTP verbs to call dedicated
actions
• Query models in order to serve
RESTful responses
Models • POST Processors
Controllers
• Create valid messages using formats
• JSON
Responses POST • XML
Processor • Etc.
@walterdalmut - www.corley.it - www.upcloo.com
14. Realize ZF2 tunneling RESTful module
• ZF1 provides «Zend_Rest_Server» that realize URI tunneling
• We can realize the same thing in 2 minutes thanks to ZF2 flexibility.
• We need to configure
• Router
• Events
• A simple example here:
• https://github.com/wdalmut/ZF2-Tunneling-Restful-Module-Skeleton
@walterdalmut - www.corley.it - www.upcloo.com
15. ZF2 URI Tunneling - Configuration
<?php
return array( We have created a simple base route «/tunnel»
'controllers' => array(
'invokables' => array( and a dynamic rule that select a «model» and an
'index' => 'TunnelingRestController',
) attached «action»
),
'router' => array(
'routes' => array(
'tunneling' => array( In simple words
'type' => 'ZendMvcRouterHttpSegment',
'options' => array( • http://my-app.local/tunnel/menu/get?id=1
'route' => '/tunnel',
'defaults' => array( • «menu»
'controller' => 'index',
'action' => 'index' • The model «TunnelingModelMenu»
),
), • «get»
'may_terminate' => true,
'child_routes' => array( • The model action «get()»
'default' => array(
'type' => 'ZendMvcRouterHttpSegment', • «id=1>
'options' => array(
'route' => '[/:model/:action]', • The action parameters «get(1)»
'constraints' => array(
'controller' => 'index',
'model' => '[a-zA-Z][a-zA-Z0-9_]*',
'action' => '[a-zA-Z][a-zA-Z0-9_]*'
),
),
),
),
),
),
)
);
@walterdalmut - www.corley.it - www.upcloo.com
16. ZF2 URI Tunneling - Controller
<?php
namespace TunnelingRest; The base «AbstractController» is very flexible
Use … and enable us to use the «dispatch» action to
class Controller extends AbstractController realize what we need in few lines.
{
public function onDispatch(MvcEvent $e)
{
$routeMatch = $e->getRouteMatch(); In practice we allocate the model and call the
$params = $routeMatch->getParams();
$vars = get_object_vars($e->getRequest()->getQuery()); requested action. The return variable is used as
$filter = new ZendFilterFilterChain(); response.
$filter->attach(new ZendFilterWordDashToCamelCase());
$filter->attach(new ZendFilterCallback("lcfirst"));
$action = $filter->filter($params["action"]);
$filter->attach(new ZendFilterCallback("ucfirst")); In case of missing model or missing action an
$model = $filter->filter($params["model"]);
«InvalidArgumentException» is thrown.
$classname = "TunnelingModel{$model}";
if (class_exists($classname)) {
$clazz = new $classname;
if (property_exists($clazz, $action)) {
$ret = call_user_func_array(array($clazz, $action), $vars);
$e->setResult($ret);
return;
} else {
throw new InvalidArgumentException("Method "{$action}" doesn't exists'");
}
} else {
throw new InvalidArgumentException("Class "{$classname}" doesn't exists'");
}
}
}
@walterdalmut - www.corley.it - www.upcloo.com
17. ZF2 URI Tunneling – Model example
<?php
namespace TunnelingModel; As you can see, the «model» is a simple class
definition.
class Menu
{
public function get($id)
{ • /tunnel/menu/get?id=1
return array("id" => $id);
} • /tunnel/menu/add?x=pizza&y=4
public function add($name, $value)
{ Very simple implementation
return array("name" => $name, "value" => $value);
}
}
@walterdalmut - www.corley.it - www.upcloo.com
18. ZF2 URI Tunneling – JSON responses
<?php
namespace Tunneling;
Thanks to events we can wire controller output
use ZendMvcMvcEvent;
to a post processor that converts responses in
class Module
json messages.
{
public function onBootstrap($e)
{
/** @var ZendModuleManagerModuleManager $moduleManager */
• Attach a «postProcess» action and create a
$moduleManager = $e->getApplication()->getServiceManager()->get('modulemanager');
/** @var ZendEventManagerSharedEventManager $sharedEvents */
json message.
$sharedEvents = $moduleManager->getEventManager()->getSharedManager();
$sharedEvents->attach(
'ZendMvcControllerAbstractController',
MvcEvent::EVENT_DISPATCH,
array($this, 'postProcess'),
-100
);
}
//…
public function postProcess(MvcEvent $e)
{
$routeMatch = $e->getRouteMatch();
if (strpos($routeMatch->getMatchedRouteName(), "tunneling") !== false) {
$e->getResponse()->setContent(json_encode($e->getResult()->getVariables()));
return $e->getResponse();
}
}
}
@walterdalmut - www.corley.it - www.upcloo.com
19. ZF2 RESTful CRUD modules
• ZF2 provides a base controller class that can help us to realize RESTful
modules in few steps
• ZendMvcControllerAbstractRestfulController
• CRUD based implementation (Extended)
• get($id)
• delete($id)
• update($id)
• create($id)
@walterdalmut - www.corley.it - www.upcloo.com
21. RESTful Controllers
<?php
• RESTful Controller should extends AbstractRestfulController
namespace MainController;
• 5 abstract methods (CRUD + List)
use ZendMvcControllerAbstractRestfulController;
• getList
class InfoController extends AbstractRestfulController
{ • GET operation without parameters
public function getList()
{ • /rest/json/info
}
return array('ciao' => 'mondo');
• Get
public function get($id) • READ resource with parameters (ID)
{
• /rest/json/info/1
}
• Delete
public function delete($id)
{ • DELETE a resource
} • Update
public function update($id, $data) • UPDATE a resource
{
• Create
}
• CREATE a new resource
public function create($data = null)
{
}
}
@walterdalmut - www.corley.it - www.upcloo.com
22. First of all play with routes
'router' => array(
'routes' => array( • Create a base route /rest that enable also formatters
'restful' => array(
'type' => 'ZendMvcRouterHttpSegment', • Formatter allow us to switch easly to JSON,
'options' => array(
'route' => '/rest[/:formatter]',
XML etc.
'constraints' => array( • Child routes play with controller and identifiers
'formatter' => '[a-zA-Z0-9_-]*',
),
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'ZendMvcRouterHttpSegment',
'options' => array(
'route' => '[/:controller[/:id]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[a-zA-Z0-9_-]*'
),
),
),
),
),
),
@walterdalmut - www.corley.it - www.upcloo.com
23. Formatters
• RESTful services can handle different type of messages
• JSON
• XML
• Images
• Etc
• The high modularity of ZF2 MVC implementation enable us to add
different layers of abstractions and formatters is one of this.
• Client must know what kind of messages type have to handle.
• Post Processors are used to render messages
@walterdalmut - www.corley.it - www.upcloo.com
24. Formatters «configs/module.config.php»
'errors' => array(
'post_processor' => 'json-pp', • The configuration allows us to define different «post processors»
'show_exceptions' => array(
'message' => true,
• Errors can be detailed more, for example traces, messages etc.
'trace' => true
)
),
'di' => array(
'instance' => array(
'alias' => array(
'json-pp' => 'MainPostProcessorJson',
'jsonp-pp' => 'MainPostProcessorJsonp',
'image-pp' => 'MainPostProcessorImage'
)
)
),
@walterdalmut - www.corley.it - www.upcloo.com
27. Example of JSON Post Processor
<?php
<?php
namespace MainPostProcessor;
namespace MainPostProcessor;
/**
abstract class AbstractPostProcessor
*
{
*/
protected $_vars = null;
class Json extends AbstractPostProcessor
private $_request = null;
{
private $_response = null;
public function process()
{
public function __construct
$result = json_encode($this->_vars);
(ZendHttpRequest $request, ZendHttpResponse $response, $vars = null)
{
$headers = $this->getResponse()->getHeaders();
$this->_vars = $vars;
$headers->addHeaderLine('Content-Type', 'application/json');
$this->_response = $response;
$this->_request = $request;
$this->getResponse()->setHeaders($headers);
}
$this->getResponse()->setContent($result);
}
public function getResponse()
}
{
return $this->_response;
}
public function getRequest()
{
return $this->_request;
}
abstract public function process();
}
@walterdalmut - www.corley.it - www.upcloo.com
28. ZF2 RESTful Modules
Thanks for listening…
Any questions?
@walterdalmut - www.corley.it - www.upcloo.com
Editor's Notes
Ringrazione l’organizzazione dello ZFDAY, gli sponsor e tutte le persone presenti.
Abbiamo solo 30 minuti quindi fare un veloce escursus sui service RESTful e vedremo come realizzare due moduli ZF2.Un primo molto semplice, ispirato a Zend_Rest_Server di ZF1 Un secondo utilizzando un componente integrato nella libreria ZF2
Il termite REST è stato coniato nel 2000 da Roy Fielding, uno degli autori del protocollo HTTP, per descrivere un sistema che permette di descrivere ed identificare le risorse web.