restful services made easy with zf2
play

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


  1. 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)

  2. 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 }

  3. 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)

  4. Services It (lazily) instantiates and holds objects.

  5. 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.

  6. 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 ' ) ;

  7. 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 )

  8. 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 ( ) , ) ) ;

  9. 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 ' , ) ) ;

  10. 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 ' , ) ) ;

  11. 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 ' ) ;

  12. 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 ' , ) ) ;

  13. 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 ' ) ) ; } ,

  14. 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 , ) ;

  15. 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 ; } }

  16. Other features • All plugin managers are services managers. • Services are shared - can disable per service. • Manager “peering” is available.

  17. 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

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

  19. Modules Provide your application with: • autoloading • configuration • services (inc controllers, plugins, etc.) • event listeners Reusable between applications - “plug & play”!

  20. 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

  21. A module is… • A PHP namespace • A class called M o d u l e within that namespace • which provides features to the application

  22. 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.

  23. 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 ) ; } }

  24. 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

  25. 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 ( )

  26. 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.

  27. 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 } }

  28. 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.

  29. RESTful ZF2 Putting REST & ZF2 together

  30. 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

  31. 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

  32. 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 } ' , ) , ) , ) ,

  33. 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 )

  34. 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 ( )

  35. 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

  36. 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 ) ;

  37. 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 ) ;

  38. 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 ) ; } ,

  39. 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 ; }

  40. 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

  41. 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

  42. 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 ) ;

  43. 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 ; }

  44. 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 ; }

  45. 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.

  46. 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

  47. 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.

  48. 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.

  49. 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

  50. 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

  51. Route • / s t a t u s / : u s e r [ / : i d ]

  52. 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

  53. 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.

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

  55. 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

  56. Review What have we learnt today?

  57. Review • REST is an architecture, with lots of recommendations but no single, canonical methodology • Don’t skimp or skip the documentation!

  58. 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

  59. Review • Several emerging standards surrounding specifically RESTful JSON APIs • Collection+JSON • Hypertext Application Language (HAL) • API-Problem

  60. 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

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend