RESTful Services made easy with ZF2 by Rob Allen and Matthew Weier - - PowerPoint PPT Presentation

restful services made easy with zf2
SMART_READER_LITE
LIVE PREVIEW

RESTful Services made easy with ZF2 by Rob Allen and Matthew Weier - - PowerPoint PPT Presentation

RESTful Services made easy with ZF2 by Rob Allen and Matthew Weier OPhinney January 2013 About us Rob Allen ZF community team @akrabat . Matthew Weier O'Phinney ZF project lead @mwop Agenda RESTful fundamentals


slide-1
SLIDE 1

RESTful Services made easy with ZF2

by Rob Allen and Matthew Weier O’Phinney January 2013

slide-2
SLIDE 2

About us

Rob Allen

  • ZF community team
  • @akrabat

. Matthew Weier O'Phinney

  • ZF project lead
  • @mwop
slide-3
SLIDE 3

Agenda

  • RESTful fundamentals
  • Zend Framework 2 fundamentals
  • RESTful ZF2
slide-4
SLIDE 4

Restful fundamentals

REpresentational State Transfer

slide-5
SLIDE 5

What is Rest?

  • An architecture
  • Centers on the transfer of representations of resources
  • A resource is any concept that can be

addressed

  • A representation is typically a document that

captures the current or intended state of a resource

  • A client makes requests of a server when it wants to

transition to a new state

slide-6
SLIDE 6

Strengths

  • Loose coupling
  • Less typing (counter-example: SOAP)
  • Emphasis on readability; uses nouns and verbs
  • HTTP methods as verbs: GET, POST, PUT,

DELETE, etc.

  • Resources as nouns, and, further, collections
slide-7
SLIDE 7

Constraints

  • Client/Server
  • Clients are not concerned with storage,

allowing them to be portable.

  • Servers are not concerned with UI or user state,

allowing scalability.

slide-8
SLIDE 8

Constraints

  • Stateless
  • No client context stored between requests.

This means no sessions!

slide-9
SLIDE 9

Constraints

  • Cacheable
  • Non-idempotent methods should allow clients to

cache responses.

  • Clients should honor HTTP headers with respect

to caching.

slide-10
SLIDE 10

Constraints

  • Layered system
  • Client should not care whether it is connected

directly to the server, or to an intermediary proxy.

slide-11
SLIDE 11

Constraints

  • Uniform Interface
  • Identification of resources
  • Manipulation of resources through

representations

  • Self-descriptive messages
  • Hypermedia as the engine of application state

(HATEOAS)

slide-12
SLIDE 12

Primary aspects of a RESTful web service

  • Base URI for each resource:

http://status.dev:8080/api/status/matthew

  • Media type used for representations of the resource
  • HTTP methods are the set of operations allowed for

the resource

  • The API must be hypertext driven (i.e., provide links

for allowed state transitions)

slide-13
SLIDE 13

Content negotiation

  • Correctly parse the request
  • Read the C o n t e n t - T y p e header
  • Raise “415 Unsupported media type” status if

unsupported

  • Correctly create the reponse
  • Read the A c c e p t header
  • Set the C o n t e n t - T y p e header
slide-14
SLIDE 14

Hypermedia

  • What is it?
  • Why is it important?
slide-15
SLIDE 15

What is hypermedia?

  • Media type used for a representation
  • The link relations between representations and/or

states

slide-16
SLIDE 16

Why is hypermedia important?

  • Discoverability
slide-17
SLIDE 17

JSON and Hypermedia

JSON does not have a defined way of providing hypermedia links Options:

  • “Link” header (GitHub approach)
  • application/collection+json
  • application/hal+json
slide-18
SLIDE 18

Link header

L i n k : < u r l > ; r e l = " r e l a t i o n " [ , . . . ]

slide-19
SLIDE 19

application/collection+json

See http://amundsen.com/media-types/collection/format/

{ " c o l l e c t i o n " : { " l i n k s " : [ { " h r e f " : " < u r i > " , " r e l " : " r e l a t i o n " } ] } }

slide-20
SLIDE 20

application/hal+json

See http://tools.ietf.org/html/draft-kelly-json-hal-03

{ " _ l i n k s " : { " r e l a t i o n " : { " h r e f " : " < u r i > " } } }

slide-21
SLIDE 21

Error reporting

  • HTTP status: 4xx, 5xx
  • No further information!
  • Solution
  • application/api-problem+json
slide-22
SLIDE 22

application/api-problem+json

See http://tools.ietf.org/html/draft-nottingham-http-problem-02

{ " d e s c r i b e d B y " : " < u r l > " , " t i t l e " : " g e n e r i c t i t l e o f e r r o r t y p e " , " h t t p S t a t u s " : < s t a t u s c o d e > , " d e t a i l " : " s p e c i f i c m e s s a g e d e t a i l i n g e r r o r " }

slide-23
SLIDE 23

Documenting your API

  • What operations are available for a given resource?
  • What do representations look like? How do I need to

form my request? What modifiers might be available?

slide-24
SLIDE 24

OPTIONS

  • Minimally, respond to O P T I O N S requests, indicating

HTTP methods allowed via the A l l o w header.

  • Potentially include information in the HTTP body.
  • http://zacstewart.com/2012/04/14/http-options-method.html
  • http://vimeo.com/49613738 (“Fun with

OPTIONS” by D. Keith Casey at REST Fest 2012)

slide-25
SLIDE 25

Using a “describedby” Link relation

  • Use a L i n k header with a “describedby” link relation

pointing to documentation. See http://www.mnot.net/blog/2012/10/29/NO_OPTIONS

L i n k : < h t t p : / / s t a t u s . d e v / a p i / s t a t u s / d o c s . m d > ; \ r e l = " d e s c r i b e d b y "

slide-26
SLIDE 26

ZF2 Fundamentals

The next generation of Zend Framework

slide-27
SLIDE 27

Highlights

  • PHP 5.3.3+ (and tested on 5.4, as well as upcoming

5.5)

  • Modular & flexible (ModuleManager)
  • Event-driven (EventManager)
  • Leverage Inversion of Control (ServiceManager)
  • Re-written MVC, Forms, I18n, Db, and more
slide-28
SLIDE 28

MVC key features

  • Everything is in a Module
  • MVC is event driven and uses ServiceManager
  • Controllers contain actions
  • which return data for your view scripts, or a

response

  • View scripts contain display code (e.g. HTML)
slide-29
SLIDE 29

Directory structure

slide-30
SLIDE 30

Module directory

slide-31
SLIDE 31

Events

Publish and listen to events

slide-32
SLIDE 32

Events

  • An object triggers an event
  • Other objects listen to events
slide-33
SLIDE 33

Terminology

  • An EventManager is an object that holds a collection
  • f listeners for one or more named events, and which

triggers events.

  • An event is an action.
  • A listener is a callback that can react to an event.
  • A Target is an object that creates events
slide-34
SLIDE 34

Simple example

u s e Z e n d \ E v e n t M a n a g e r \ E v e n t M a n a g e r , Z e n d \ E v e n t M a n a g e r \ E v e n t ; $ c a l l b a c k = f u n c t i o n ( $ e v e n t ) { e c h o " A n e v e n t h a s h a p p e n e d ! \ n " ; v a r _ d u m p ( $ e v e n t - > g e t N a m e ( ) ) ; } ; $ e v e n t s = n e w E v e n t M a n a g e r ( ) ; $ e v e n t s - > a t t a c h ( ' e v e n t N a m e ' , $ c a l l b a c k ) ; e c h o " \ n R a i s e a n e v e n t \ n " ; $ e v e n t s - > t r i g g e r ( ' e v e n t N a m e ' ) ;

slide-35
SLIDE 35

Listeners

Just a function (Any callback)

$ c a l l b a c k = f u n c t i o n ( $ e v e n t ) { e c h o " A n e v e n t h a s h a p p e n e d ! \ n " ; v a r _ d u m p ( $ e v e n t - > g e t N a m e ( ) ) ; v a r _ d u m p ( $ e v e n t - > g e t T a r g e t ( ) ) ; v a r _ d u m p ( $ e v e n t - > g e t P a r a m s ( ) ) ; } ; $ e v e n t s = $ s o m e O b j e c t - > g e t E v e n t M a n a g e r ( ) ; $ e v e n t s - > a t t a c h ( ' e v e n t N a m e ' , $ c a l l b a c k ) ;

slide-36
SLIDE 36

The target

Compose an EventManager within a class…

u s e Z e n d \ E v e n t M a n a g e r \ E v e n t M a n a g e r , Z e n d \ E v e n t M a n a g e r \ E v e n t ; c l a s s M y T a r g e t { p u b l i c $ e v e n t s ; p u b l i c f u n c t i o n _ _ c o n s t r u c t ( ) { $ t h i s - > e v e n t s = n e w E v e n t M a n a g e r ( ) ; } / / . . .

slide-37
SLIDE 37

The target

… and trigger actions within methods.

p u b l i c f u n c t i o n d o I t ( ) { $ e v e n t = n e w E v e n t ( ) ; $ e v e n t - > s e t T a r g e t ( $ t h i s ) ; $ e v e n t - > s e t P a r a m ( ' o n e ' , 1 ) ; $ t h i s - > e v e n t s - > t r i g g e r ( ' d o I t . p r e ' , $ e v e n t ) ; / / d o s o m e t h i n g h e r e $ t h i s - > e v e n t s - > t r i g g e r ( ' d o I t . p o s t ' , $ e v e n t ) ; }

slide-38
SLIDE 38

Typical usage

$ c a l l b a c k = f u n c t i o n ( $ e v e n t ) { e c h o " R e s p o n d i n g t o d o I t . p r e ! \ n " ; v a r _ d u m p ( g e t _ c l a s s ( $ e v e n t - > g e t T a r g e t ( ) ) ) ; v a r _ d u m p ( $ e v e n t - > g e t N a m e ( ) ) ; v a r _ d u m p ( $ e v e n t - > g e t P a r a m s ( ) ) ; } ; $ t a r g e t = n e w M y T a r g e t ( ) ; $ t a r g e t - > e v e n t s - > a t t a c h ( ' d o I t . p r e ' , $ c a l l b a c k ) ; $ t a r g e t - > d o I t ( ) ;

slide-39
SLIDE 39

Attaching listeners globally

  • Listeners are used for cross-cutting concerns
  • You want to set up listeners before you instantiation
  • f object with event manager
  • For example: logging, caching
slide-40
SLIDE 40

SharedEventManager

Attach a listener to another class’ event manager

$ s h a r e d = $ e v e n t s - > g e t S h a r e d M a n a g e r ( ) ; / / o r $ s h a r e d = S t a t i c E v e n t M a n a g e r : : g e t I n s t a n c e ( ) ; $ s h a r e d - > a t t a c h ( ' G a l l e r y \ \ M a p p e r \ \ P h o t o ' , ' f i n d B y I d . p r e ' , f u n c t i o n ( E v e n t $ e ) { $ i d = $ e - > g e t P a r a m ( ' i d ' ) ; $ m e s s a g e = " R e t r i e v i n g p h o t o : $ i d " ; M y L o g g e r : : l o g ( $ m e s s a g e ) ; } ) ;

slide-41
SLIDE 41

Returned values from listeners

p u b l i c f u n c t i o n d o I t ( ) { $ e v e n t s = $ t h i s - > e v e n t s ; $ r e s u l t s = $ e v e n t s - > t r i g g e r ( ' d o I t ' , $ t h i s ) ; f o r e a c h ( $ r e s u l t s a s $ r e s u l t ) { v a r _ d u m p ( $ r e s u l t ) ; } }

$ r e s u l t s are in reverse order

(most recently triggered event first)

slide-42
SLIDE 42

Short-circuiting

$ p a r a m s = a r r a y ( ' i d ' = > 1 ) ; $ r e s u l t s = $ t h i s - > e v e n t s - > t r i g g e r ( ' d o I t . p r e ' , $ t h i s , $ p a r a m s , f u n c t i o n ( $ r e s u l t ) { i f ( $ r e s u l t i n s t a n c e o f R e s u l t S e t ) { r e t u r n t r u e ; } r e t u r n f a l s e ; } ) ; i f ( $ r e s u l t s - > s t o p p e d ( ) ) { / / W e e n d e d e a r l y }

slide-43
SLIDE 43

Priority

  • Control the order of execution of listeners
  • $priority is last parameter to attach()

$ e v e n t s - > a t t a c h ( ' d o I t . p r e ' , $ c b , $ p r i o r i t y ) ;

  • Default is 1
  • Larger number increases priority (e.g. 1000)
  • Smaller number decreases priority (e.g. -500)
slide-44
SLIDE 44

Services

It (lazily) instantiates and holds objects.

slide-45
SLIDE 45

Services

  • Objects you work with (including Controllers).
  • Easy to replace alternative implementations.
  • Clean and simple way to configure dependencies.
  • Explicit and easy to understand - no magic!
  • Inversion of Control.
slide-46
SLIDE 46

Usage

$ c o n t r o l l e r = $ s m - > g e t ( ' G a l l e r y \ M a p p e r \ P h o t o ' ) ;

slide-47
SLIDE 47

Types of services

  • Instances (s e r v i c e s )
  • Constructor-less classes (i n v o k a b l e s )
  • Factories for objects with dependencies (f a c t o r i e s )
  • Aliased services (a l i a s e s )
  • Automated initialization (i n i t i a l i z e r s )
  • Factories for multiple related objects

(a b s t r a c t _ f a c t o r i e s )

slide-48
SLIDE 48

Instances

/ / p r o g r a m a t i c a l l y $ s m - > s e t S e r v i c e ( ' f o o ' , $ f o o I n s t a n c e ) ; / / c o n f i g u r a t i o n a r r a y ( ' s e r v i c e s ' = > a r r a y ( ' f o o ' = > n e w F o o ( ) , ) ) ;

slide-49
SLIDE 49

Invokables

/ / p r o g r a m a t i c a l l y $ s m - > s e t I n v o k a b l e C l a s s ( ' f o o ' , ' B a r \ F o o ' ) ; / / c o n f i g u r a t i o n a r r a y ( ' i n v o k a b l e s ' = > a r r a y ( ' f o o ' = > ' B a r \ F o o ' , ) ) ;

slide-50
SLIDE 50

Factories

/ / p r o g r a m a t i c a l l y $ s m - > s e t F a c t o r y ( ' f o o ' , f u n c t i o n ( $ s m ) { $ d e p e n d e n c y = $ s m - > g e t ( ' D e p e n d e n c y ' ) r e t u r n n e w F o o ( $ d e p e n d e n c y ) ; } ) ; / / c o n f i g u r a t i o n a r r a y ( ' f a c t o r i e s ' = > a r r a y ( ' f o o ' = > f u n c t i o n ( $ s m ) { / / . . } , ' b a r ' = > ' S o m e \ S t a t i c : : m e t h o d ' , ' b a z ' = > ' C l a s s \ I m p l e m e n t i n g \ F a c t o r y I n t e r f a c e ' , ' b a t ' = > ' C l a s s \ I m p l e m e n t i n g \ I n v o k e ' , ) ) ;

slide-51
SLIDE 51

Aliases

/ / p r o g r a m a t i c a l l y $ s m - > s e t A l i a s ( ' f o o _ d b ' , ' d b _ a d a p t e r ' ) ; / / c o n f i g u r a t i o n a r r a y ( ' f a c t o r i e s ' = > a r r a y ( ' f o o _ d b ' , ' d b _ a d a p t e r ' , / / a l i a s o f a s e r v i c e ' b a r _ d b ' , ' f o o _ d b ' , / / a l i a s o f a n a l i a s ) ) ; / / A l l t h e s a m e i n s t a n c e $ d b = $ s m - > g e t ( ' d b _ a d a p t e r ' ) ; $ d b = $ s m - > g e t ( ' f o o _ d b ' ) ; $ d b = $ s m - > g e t ( ' b a r _ d b ' ) ;

slide-52
SLIDE 52

Initializers

/ / p r o g r a m a t i c a l l y $ s m - > a d d I n i t i a l i z e r ( $ c a l l b a c k ) ; / / c o n f i g u r a t i o n a r r a y ( ' i n i t i a l i z e r s ' = > a r r a y ( $ i n s t a n c e , $ c a l l b a c k , ' C l a s s \ I m p l e m e n t i n g \ I n i t i a l i z e r I n t e r f a c e ' , ' C l a s s \ I m p l e m e n t i n g \ I n v o k e ' , ) ) ;

slide-53
SLIDE 53

An initializer

f u n c t i o n ( $ i n s t a n c e , $ s m ) { i f ( $ i n s t a n c e i n s t a n c e o f F o o A w a r e I n t e r f a c e ) { r e t u r n ; } $ i n s t a n c e - > s e t F o o ( $ s m - > g e t ( ' f o o ' ) ) ; } ,

slide-54
SLIDE 54

Abstract factories

Factory capable of handling multiple services

/ / p r o g r a m a t i c a l l y $ s m - > a d d A b s t r a c t F a c t o r y ( $ a b s t r a c t F a c t o r y I n s t a n c e ) ; $ s m - > a d d A b s t r a c t F a c t o r y ( ' F o o F a c t o r y ' ) ; / / c o n f i g u r a t i o n a r r a y ( ' a b s t r a c t _ f a c t o r i e s ' = > a r r a y ( ' C l a s s \ I m p l e m e n t i n g \ A b s t r a c t F a c t o r y I n t e r f a c e ' , $ s o m e A b s t r a c t F a c t o r y I n s t a n c e , ) ;

slide-55
SLIDE 55

An abstract factory

c l a s s A F a c t o r y i m p l e m e n t s A b s t r a c t F a c t o r y I n t e r f a c e { p u b l i c f u n c t i o n c a n C r e a t e S e r v i c e W i t h N a m e ( S e r v i c e L o c a t o r I n t e r f a c e $ s e r v i c e s , $ n a m e , $ r e q u e s t e d N a m e ) { r e t u r n i n _ a r r a y ( $ n a m e , a r r a y ( ' f o o ' , ' b a r ' ) ; } p u b l i c f u n c t i o n c r e a t e S e r v i c e W i t h N a m e ( / * s i g * / ) { r e t u r n $ n a m e = = ' f o o ' ? n e w F o o : n e w B a r ; } }

slide-56
SLIDE 56

Other features

  • All plugin managers are services managers.
  • Services are shared - can disable per service.
  • Manager “peering” is available.
slide-57
SLIDE 57

Configuration in practice

  • A nested array in:
  • MyModuleModule::getServiceConfig()
  • ‘service_manager’ array key in config
  • sub-array keys : s e r v i c e s , i n v o k a b l e s , f a c t o r i e s ,

a l i a s e s , i n i t i a l i z e r s , a b s t r a c t _ f a c t o r i e s

slide-58
SLIDE 58

Modules

Re-usable pieces of functionality for constructing a more complex application.

slide-59
SLIDE 59

Modules

Provide your application with:

  • autoloading
  • configuration
  • services (inc controllers, plugins, etc.)
  • event listeners

Reusable between applications - “plug & play”!

slide-60
SLIDE 60

What can modules be?

Anything!

  • Plugins: payment module for e-commerce
  • View helpers: Markdown support
  • Themes: CSS files, images, view scripts
  • Libraries: Doctrine2 integration, RESTful support
  • Applications: blog, e-commerce platform, CMS
slide-61
SLIDE 61

A module is…

  • A PHP namespace
  • A class called M o d u l e within that namespace
  • which provides features to the application
slide-62
SLIDE 62

A ZF2 Module

< ? p h p n a m e s p a c e M y M o d u l e ; c l a s s M o d u l e { }

That’s it.

slide-63
SLIDE 63

A complete ZF2 module

n a m e s p a c e E d p M a r k d o w n ; c l a s s M o d u l e e x t e n d s \ Z e n d \ V i e w \ H e l p e r \ A b s t r a c t H e l p e r { p u b l i c f u n c t i o n g e t V i e w H e l p e r C o n f i g ( ) { r e t u r n a r r a y ( ' s e r v i c e s ' = > a r r a y ( ' m a r k d o w n ' = > $ t h i s ) ) ; } p u b l i c f u n c t i o n _ _ i n v o k e ( $ s t r i n g = n u l l ) { r e q u i r e _ o n c e _ _ D I R _ _ . ' m a r k d o w n . p h p ' ; r e t u r n M a r k d o w n ( $ s t r i n g ) ; } }

slide-64
SLIDE 64

ModuleManager

  • Loads all modules
  • Triggers an event for each module
  • allowing listeners to act on Module classes
  • Results in calls specific methods within your

M o d u l e class

slide-65
SLIDE 65

Module methods called

  • g e t A u t o l o a d e r C o n f i g ( )
  • i n i t ( )
  • o n B o o t s t r a p ( )
  • Service Manager methods:
  • g e t S e r v i c e C o n f i g ( )
  • g e t C o n t r o l l e r C o n f i g ( )
  • g e t C o n t r o l l e r P l u g i n C o n f i g ( )
  • g e t V i e w H e l p e r C o n f i g ( )
slide-66
SLIDE 66

Other actions

  • If L o c a t o r R e g i s t e r e d I n t e r f a c e is implemented,

then register with the service manager.

  • All configs are merged together:
  • 1. g e t C o n f i g ( ) results merged in the order

modules are loaded.

  • 2. Config glob/static paths are merged.
  • 3. The g e t S e r v i c e C o n f i g ( ) (and friends) results

are merged together then merged with the result of steps 1 and 2.

slide-67
SLIDE 67

A typical Module class

n a m e s p a c e M y ; c l a s s M o d u l e { p u b l i c f u n c t i o n g e t A u t o l o a d e r C o n f i g ( ) { / / r e t u r n c o n f i g f o r a u t o l o a d e r f a c t o r y } p u b l i c f u n c t i o n g e t C o n f i g ( ) { r e t u r n i n c l u d e _ _ D I R _ _ . ' / c o n f i g / m o d u l e . c o n f i g . p h p ' ; } p u b l i c f u n c t i o n o n B o o t s t r a p ( $ e ) { / / d o i n i t i a l i z a t i o n } }

slide-68
SLIDE 68

Module best practices

  • Keep i n i t ( ) and o n B o o t s t r a p ( ) very lightweight.
  • Read-only (do not perform writes within modules).
  • Utilize a vendor prefix (e.g., E d p M a r k d o w n , not

M a r k d o w n ).

  • Do one thing, and do it well.
slide-69
SLIDE 69

RESTful ZF2

Putting REST & ZF2 together

slide-70
SLIDE 70

Foundations

  • Routing
  • A b s t r a c t R e s t f u l C o n t r o l l e r
  • Reacting to request headers
  • Creating hypermedia payloads
  • Creating error payloads
slide-71
SLIDE 71

Routing

  • Route to an A b s t r a c t R e s t f u l C o n t r o l l e r

implementation

  • Allows a single route to manage all HTTP

methods for a given resource

  • Use a combination of Literal and/or Segment routes
slide-72
SLIDE 72

Sample Route

' s t a t u s ' = > a r r a y ( ' t y p e ' = > ' S e g m e n t ' , ' o p t i o n s ' = > a r r a y ( ' r o u t e ' = > ' / a p i / s t a t u s [ / : i d ] ' , ' d e f a u l t s ' = > a r r a y ( ' c o n t r o l l e r ' = > ' S t a t u s C o n t r o l l e r ' , ) , ' c o n s t r a i n t s ' = > a r r a y ( ' i d ' = > ' [ a - f 0 - 9 ] { 4 0 } ' , ) , ) , ) ,

slide-73
SLIDE 73

AbstractRestfulController

  • Maps HTTP methods to individual class methods
  • Performs basic content-negotiation

(a p p l i c a t i o n / w w w - f o r m - u r l e n c o d e d and JSON bodies will be parsed and provided as $ d a t a )

slide-74
SLIDE 74

Mapping methods

  • G E T :: g e t L i s t ( ) or g e t ( $ i d )
  • P O S T :: c r e a t e ( $ d a t a )
  • P U T :: r e p l a c e L i s t ( ) , u p d a t e ( $ i d , $ d a t a )
  • P A T C H :: p a t c h ( $ i d , $ d a t a )
  • D E L E T E :: d e l e t e L i s t ( ) , d e l e t e ( $ i d )
  • H E A D :: h e a d ( $ i d = n u l l )
  • O P T I O N S :: o p t i o n s ( )
slide-75
SLIDE 75

Selecting an acceptable view model

  • Select a view model based on A c c e p t
  • Attach a view strategy based on view model
slide-76
SLIDE 76

AcceptableViewModelSelector

  • Controller plugin

$ c r i t e r i a = a r r a y ( ' Z e n d \ V i e w \ M o d e l \ J s o n M o d e l ' = > a r r a y ( ' \ * / j s o n ' , ) , ) ; $ m o d e l = $ t h i s - > a c c e p t a b l e V i e w M o d e l ( $ c r i t e r i a ) ;

slide-77
SLIDE 77

Changing view strategy based on model

  • Listen on the controller’s dispatch event

$ s h a r e d E v e n t s - > a t t a c h ( ' Z e n d \ M v c \ C o n t r o l l e r \ A b s t r a c t R e s t f u l C o n t r o l l e r ' , ' d i s p a t c h ' , $ l i s t e n e r

  • 1 0

) ;

slide-78
SLIDE 78

Sample listener

f u n c t i o n ( M v c E v e n t $ e ) { $ r e s u l t = $ e - > g e t R e s u l t ( ) ; i f ( ! $ r e s u l t i n s t a n c e o f J s o n M o d e l ) { r e t u r n ; } $ a p p = $ e - > g e t A p p l i c a t i o n ( ) ; $ s e r v i c e s = $ a p p - > g e t S e r v i c e M a n a g e r ( ) ; $ s t r a t e g y = $ s e r v i c e s - > g e t ( ' V i e w J s o n S t r a t e g y ' ) ; $ v i e w = $ s e r v i c e s - > g e t ( ' V i e w ' ) ; $ v i e w - > a t t a c h ( $ s t r a t e g y , 1 0 0 ) ; } ,

slide-79
SLIDE 79

Directly examining the Accept header

$ h e a d e r s = $ r e q u e s t - > g e t H e a d e r s ( ) ; i f ( ! $ h e a d e r s - > h a s ( ' A c c e p t ' ) ) { / / n o A c c e p t h e a d e r ; d o d e f a u l t r e t u r n ; } $ a c c e p t = $ h e a d e r s - > g e t ( ' A c c e p t ' ) ; i f ( $ a c c e p t - > m a t c h ( $ m e d i a T y p e ) ) { / / w e h a v e a m a t c h ! r e t u r n ; }

slide-80
SLIDE 80

Hypermedia payloads

  • Links should be fully qualified: include, scheme,

server, and port if necessary

  • A s e l f relation is recommended
  • With paginated sets, include f i r s t , l a s t , n e x t , and

p r e v relations

slide-81
SLIDE 81

Tools for creating links

  • The u r l controller plugin and/or view helper can

generate the path if a route is known.

  • The s e r v e r U r l view helper can generate the

scheme/server/port combination

  • Paginators can be inspected and used to generate

pagination relations

slide-82
SLIDE 82

Generating individual links

$ p a t h = $ u r l H e l p e r - > f r o m R o u t e ( $ r o u t e , a r r a y ( ' i d ' = > $ i d , ) ) ; $ u r l = $ s e r v e r U r l H e l p e r - > _ _ i n v o k e ( $ p a t h ) ;

slide-83
SLIDE 83

Generating paginated links

/ / $ p a g e i s t h e c u r r e n t p a g e / / $ c o u n t i s t h e t o t a l n u m b e r o f p a g e s / / $ b a s e i s t h e b a s e U R L t o t h e r e s o u r c e $ n e x t = ( $ p a g e = = $ c o u n t ) ? f a l s e : $ p a g e + 1 ; $ p r e v = ( $ p a g e = = 1 ) ? f a l s e : $ p a g e - 1 ; $ l i n k s = a r r a y ( ' s e l f ' = > $ b a s e . ( 1 = = $ p a g e ? ' ' : ' ? p = ' . $ p a g e ) , ) ; i f ( $ p a g e ! = 1 ) { $ l i n k s [ ' f i r s t ' ] = $ b a s e ; }

slide-84
SLIDE 84

cont…

i f ( $ c o u n t ! = 1 ) { $ l i n k s [ ' l a s t ' ] = $ b a s e . ' ? p = ' . $ c o u n t ; } i f ( $ p r e v ) { $ l i n k s [ ' p r e v ' ] = $ b a s e . ( ( 1 = = $ p r e v ) ? ' ' : ' ? p = ' . $ p r e v ; } i f ( $ n e x t ) { $ l i n k s [ ' n e x t ' ] = $ b a s e . ' ? p = ' . $ n e x t ; }

slide-85
SLIDE 85

Where to generate links

  • Controller is easiest, but may not be semantically

correct

  • View model makes sense, but is hard to inject with

helpers

  • Renderer makes sense, but likely requires specialized

payloads in the view model

  • A event listener could process the view model and

inject them; similar issues to the renderer, though.

  • Choose your poison.
slide-86
SLIDE 86

Error payloads

  • Be consistent
  • Provide detail
  • a p p l i c a t i o n / a p i - p r o b l e m + j s o n is a nice standard
slide-87
SLIDE 87

API-Problem payloads

  • d e s c r i b e d b y is required. If corresponding to HTTP

status, http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html describing HTTP status codes is a nice default.

  • t i t l e is also required; again, if corresponding to

HTTP status, use established status descriptions.

  • h t t p S t a t u s is not required, but recommended.
  • d e t a i l is your place to provide any additional

information.

slide-88
SLIDE 88

Where to generate API-Problem payloads

  • Typically, within the controller; this is where the

errors happen.

  • You may also want listeners on d i s p a t c h . e r r o r so

you can generate 404 responses in this format.

slide-89
SLIDE 89

Practical application

  • YOU will build a simple “status” API for posting

social status

  • “text” representing the status
  • “user” representing the user posting the status
  • “timestamp” when the status was created
  • Collection of statuses by user, in reverse

chronological order

  • User is present in the URI
slide-90
SLIDE 90

Steps

  • Create the domain logic (this is the hard part)
  • Create a route
  • Create a controller that:
  • calls on the domain logic
  • varies the view model based on the A c c e p t

header

  • creates API-Problem payloads for errors
  • Create a listener for injecting hypermedia links in the

view model

slide-91
SLIDE 91

Route

  • / s t a t u s / : u s e r [ / : i d ]
slide-92
SLIDE 92

Controller

  • Extend A b s t r a c t R e s t f u l C o n t r o l l e r
  • use A c c e p t a b l e V i e w M o d e l S e l e c t o r to pull a

relevant view model based on A c c e p t header; create a special view model type that we can listen for later.

  • set specific variables in the view that we can

query later

  • use a special object for indicating errors
  • set appropriate HTTP status codes
slide-93
SLIDE 93

Listener

  • Listen for our special view model type
  • If an error is detected:
  • Create an API-Problem payload
  • Set the response status code
  • Generate hyperlinks based on whether we have a

collection or an individual item.

slide-94
SLIDE 94

Demonstration

This is meant to be alive demo of the finished API, and maybe some code samples.

slide-95
SLIDE 95

PhlyRestfully

  • Module that does these bits for you
  • Add it to composer
  • “phly/phly-restfully”: “dev-master@dev”
  • Provide a resource listener that does the various

persistence related operations and a route, and go. test

slide-96
SLIDE 96

Review

What have we learnt today?

slide-97
SLIDE 97

Review

  • REST is an architecture, with lots of recommendations

but no single, canonical methodology

  • Don’t skimp or skip the documentation!
slide-98
SLIDE 98

Review

  • REST has lots of little details to pay attention to:
  • URIs per resource
  • HTTP methods indicating the operations

available for a resource

  • Media types indicating resource

representations govern how to parse a request as well as how to format a response

  • Hypermedia links to promote discoverability

and available state changes

slide-99
SLIDE 99

Review

  • Several emerging standards surrounding specifically

RESTful JSON APIs

  • Collection+JSON
  • Hypertext Application Language (HAL)
  • API-Problem
slide-100
SLIDE 100

Review

  • ZF2 has a lot of built-in features to help build RESTful

applications

  • A b s t r a c t R e s t f u l C o n t r o l l e r
  • A c c e p t header implementation
  • Rich HTTP tooling in general
  • Flexible view layer
slide-101
SLIDE 101

Thank you!

https://joind.in/7781

Rob Allen : http://akrabat.com : @akrabat Matthew Weier O’Phinney : http://mwop.net : @mwop