Slide 1

Slide 1 text

THE QUICKEST WAY TO STABLE API USING LARAVEL FRAMEWORK Presented by / Milan Popović @komita1981

Slide 2

Slide 2 text

ME PHP developer Work for Navus Consulting Gmbh I like to learn and share knowledge Active member of PHP Srbija

Slide 3

Slide 3 text

Why Laravel? Enables rapid development Stable and well tested Community support Documentation Learning resources Easy to recruit developers LTS

Slide 4

Slide 4 text

Why Laravel for quick API development? DB Migration DB seeding Model factory Form request Testing 3rd Party Packages

Slide 5

Slide 5 text

DB MIGRATION Version control for you DB schema Laravel Schema facade provides database agnostic support for creating and manipulating tables / / C r e a t e n e w m i g r a t i o n p h p a r t i s a n m a k e : m i g r a t i o n c r e a t e _ u s e r s _ t a b l e / / R u n m i g r a t i o n p h p a r t i s a n m i g r a t e / / R o l l b a c k m i g r a t i o n p h p a r t i s a n m i g r a t e

Slide 6

Slide 6 text

DB SEED Sample/Test data for your DB / / C r e a t e n e w s e e d e r p h p a r t i s a n m a k e : s e e d e r U s e r s T a b l e S e e d e r / / R u n s e e d e r s p h p a r t i s a n d b : s e e d / / R u n s e e d e r s v 2 p h p a r t i s a n m i g r a t e - - s e e d / / R u n s i n g l e s e e d e r p h p a r t i s a n d b : s e e d - - c l a s s = U s e r s T a b l e S e e d e r

Slide 7

Slide 7 text

MODEL FACTORY Default model attributes Uses Faker for generating values $ f a c t o r y - > d e f i n e ( A p p \ U s e r : : c l a s s , f u n c t i o n ( F a k e r \ G e n e r a t o r $ f a k e r ) { r e t u r n [ ' n a m e ' = > $ f a k e r - > n a m e , ' e m a i l ' = > $ f a k e r - > e m a i l , ' p a s s w o r d ' = > b c r y p t ( s t r _ r a n d o m ( 1 0 ) ) , ' r e m e m b e r _ t o k e n ' = > s t r _ r a n d o m ( 1 0 ) , ] ; } ) ;

Slide 8

Slide 8 text

Multiple Factory Types - multiple factories for the same Eloquent model class $ f a c t o r y - > d e f i n e A s ( A p p \ U s e r : : c l a s s , ' a d m i n ' , f u n c t i o n ( $ f a k e r ) u s e ( $ f a c t o r y $ u s e r = $ f a c t o r y - > r a w ( A p p \ U s e r : : c l a s s ) ; r e t u r n a r r a y _ m e r g e ( $ u s e r , [ ' a d m i n ' = > t r u e ] ) ; } ) ;

Slide 9

Slide 9 text

Attach relationships $ f a c t o r y - > d e f i n e ( A p p \ P o s t : : c l a s s , f u n c t i o n ( $ f a k e r ) { r e t u r n [ ' t i t l e ' = > $ f a k e r - > t i t l e , ' c o n t e n t ' = > $ f a k e r - > p a r a g r a p h , ' u s e r _ i d ' = > f u n c t i o n ( ) { r e t u r n f a c t o r y ( A p p \ U s e r : : c l a s s ) - > c r e a t e ( ) - > i d ; } , ' u s e r _ t y p e ' = > f u n c t i o n ( a r r a y $ p o s t ) { r e t u r n A p p \ U s e r : : f i n d ( $ p o s t [ ' u s e r _ i d ' ] ) - > t y p e ; } ] ; } ) ;

Slide 10

Slide 10 text

Using factories / / C r e a t e t h r e e A p p \ U s e r i n s t a n c e s . . . $ u s e r s = f a c t o r y ( A p p \ U s e r : : c l a s s , 3 ) - > m a k e ( ) ; / / C r e a t e t h r e e A p p \ U s e r " a d m i n " i n s t a n c e s . . . $ u s e r s = f a c t o r y ( A p p \ U s e r : : c l a s s , ' a d m i n ' , 3 ) - > m a k e ( ) ; / / C r e a t e A p p \ U s e r u s e r w i t h g i v e n n a m e . . . $ u s e r = f a c t o r y ( A p p \ U s e r : : c l a s s ) - > m a k e ( [ ' n a m e ' = > ' A b i g a i l ' , ] ) ; / / P e r s i s t i n g F a c t o r y M o d e l s $ u s e r = f a c t o r y ( A p p \ U s e r : : c l a s s ) - > c r e a t e ( ) ;

Slide 11

Slide 11 text

FORM REQUESTS Special class for validating request params and authorizing Each class has rules() (returns array) and authorize() (returns boolean) methods Type Hinting in Controller methods

Slide 12

Slide 12 text

p u b l i c f u n c t i o n r u l e s ( ) { r e t u r n [ ' t i t l e ' = > ' r e q u i r e d | u n i q u e : p o s t s | m a x : 2 5 5 ' , ' b o d y ' = > ' r e q u i r e d ' , ] ; } p u b l i c f u n c t i o n a u t h o r i z e ( ) { $ c o m m e n t I d = $ t h i s - > r o u t e ( ' c o m m e n t ' ) ; r e t u r n C o m m e n t : : w h e r e ( ' i d ' , $ c o m m e n t I d ) - > w h e r e ( ' u s e r _ i d ' , A u t h : : i d ( ) ) - > e x i s t s ( ) ; }

Slide 13

Slide 13 text

TESTING PHPUnit is included out of the box Laravel is built with testing in mind It's also ships with convenient helper methods Uses Mockery as mock object framework

Slide 14

Slide 14 text

WORKING WITH DATABASE Using Migrations - DatabaseMigrations trait DatabaseTransactions - DatabaseTransactions trait Model Factories

Slide 15

Slide 15 text

WORKING WITH DATABASE SeeInDatabase helper seeInDatabase($table, array $data, $connection = null) NotSeeInDatabase helper notSeeInDatabase($table, array $data, $connection = null) Seed (seed($class = 'DatabaseSeeder')

Slide 16

Slide 16 text

CREATING HTTP REQUEST / / M a i n m e t h o d p u b l i c f u n c t i o n c a l l ( $ m e t h o d , $ u r i , $ p a r a m e t e r s = [ ] , $ c o o k i e s = [ ] , $ f i l e s = / / T h e r e a r e a l s o m e t h o d s f o r o t h e r h t t p v e r b s p u b l i c f u n c t i o n p o s t ( $ u r i , a r r a y $ d a t a = [ ] , a r r a y $ h e a d e r s = [ ] ) / / V i s i t t h e g i v e n U R I w i t h a J S O N r e q u e s t . p u b l i c f u n c t i o n j s o n ( $ m e t h o d , $ u r i , a r r a y $ d a t a = [ ] , a r r a y $ h e a d e r s = [ ] ) { / / r e m o v e d c o d e f r o m o r i g i n a l m e t h o d $ c o n t e n t = j s o n _ e n c o d e ( $ d a t a ) ; $ h e a d e r s = a r r a y _ m e r g e ( [ ' C O N T E N T _ L E N G T H ' = > m b _ s t r l e n ( $ c o n t e n t , ' 8 b i t ' ) , ' C O N T E N T _ T Y P E ' = > ' a p p l i c a t i o n / j s o n ' , ' A c c e p t ' = > ' a p p l i c a t i o n / j s o n ' , ] , $ h e a d e r s ) ;

Slide 17

Slide 17 text

PHPUNIT ASSERTIONS FOR STATUS CODE AND HEADERS assertResponseOk() assertResponseStatus($code) seeStatusCode($status) seeHeader($headerName, $value)

Slide 18

Slide 18 text

PHPUNIT ASSERTIONS FOR JSON seeJsonEquals($data) seeJsonStructure($structure, $responseData) seeJsonContains($data, $negate) seeJsonSubset($data)

Slide 19

Slide 19 text

PACKAGES & TOOLS Dingo API Dredd Repositories CORS

Slide 20

Slide 20 text

DINGO API " r e q u i r e " : { " d i n g o / a p i " : " 1 . 0 . * @ d e v " } Provides set of tools to easily and quickly build your own API Requires Laravel 5.1+ or Lumen 5.1+ and PHP 5.5.9+

Slide 21

Slide 21 text

CONFIGURATION Much of the package comes preconfigured Use your .env file to configure most of the package Finer tuning of the package will require publishing the configuration file

Slide 22

Slide 22 text

Configure: Name Default Version Authentication Provider Throttling / Rate Limiting (Disabled by default) Response Transformer (Fractal is the default) Response Format (JSON and a JSON response format is registered by default) Error Format

Slide 23

Slide 23 text

CREATING API ENDPOINTS / / T o a v o i d c o m p l i c a t i o n s w i t h y o u r m a i n a p p l i c a t i o n r o u t e s t h i s p a c k a g e u t i l $ a p i = a p p ( ' D i n g o \ A p i \ R o u t i n g \ R o u t e r ' ) ; $ a p i - > v e r s i o n ( ' v 1 ' , f u n c t i o n ( $ a p i ) { $ a p i - > p o s t ( ' r e g i s t e r ' , ' S a m p l e A p i \ H t t p \ C o n t r o l l e r s \ R e g i s t e r C o n t r o l l e r $ a p i - > p o s t ( ' l o g i n ' , ' S a m p l e A p i \ H t t p \ C o n t r o l l e r s \ L o g i n C o n t r o l l e r @ l o g i n $ a p i - > g e t ( ' b l o c k s ' , ' S a m p l e A p i \ H t t p \ C o n t r o l l e r s \ B l o c k s C o n t r o l l e r @ g e t A $ a p i - > g e t ( ' b l o c k s / { i d } ' , ' S a m p l e A p i \ H t t p \ C o n t r o l l e r s \ B l o c k s C o n t r o l l e r $ a p i - > p o s t ( ' b l o c k s ' , ' S a m p l e A p i \ H t t p \ C o n t r o l l e r s \ B l o c k s C o n t r o l l e r @ c r e $ a p i - > p u t ( ' b l o c k s / { i d } ' , ' S a m p l e A p i \ H t t p \ C o n t r o l l e r s \ B l o c k s C o n t r o l l e r $ a p i - > d e l e t e ( ' b l o c k s / { i d } ' , ' S a m p l e A p i \ H t t p \ C o n t r o l l e r s \ B l o c k s C o n t r o l } ) ;

Slide 24

Slide 24 text

RESPONSES There's a number of different ways to return responses Use Response Builder Provides a fluent interface to easily build a more customizable response Generally used in conjunction with transformers. Use the Dingo\Api\Routing\Helpers trait

Slide 25

Slide 25 text

u s e D i n g o \ A p i \ R o u t i n g \ H e l p e r s ; u s e I l l u m i n a t e \ R o u t i n g \ C o n t r o l l e r ; c l a s s A p i C o n t r o l l e r e x t e n d s C o n t r o l l e r { u s e H e l p e r s ; }

Slide 26

Slide 26 text

RESPONDING WITH AN ARRAY p u b l i c f u n c t i o n s h o w ( $ i d ) { $ b l o c k = $ t h i s - > b l o c k - > f i n d ( $ i d ) ; r e t u r n $ t h i s - > r e s p o n s e - > a r r a y ( $ b l o c k - > t o A r r a y ( ) ) ; }

Slide 27

Slide 27 text

RESPONDING WITH A SINGLE ITEM p u b l i c f u n c t i o n s h o w ( $ i d ) { $ b l o c k = $ t h i s - > b l o c k - > f i n d ( $ i d ) ; r e t u r n $ t h i s - > r e s p o n s e - > i t e m ( $ b l o c k , n e w B l o c k T r a n s f o r m e r ) ; }

Slide 28

Slide 28 text

RESPONDING WITH A COLLECTION OF ITEMS p u b l i c f u n c t i o n s h o w ( $ i d ) { $ b l o c k s = $ t h i s - > b l o c k - > f i n d ( $ i d ) ; r e t u r n $ t h i s - > r e s p o n s e - > c o l l e c t i o n ( $ b l o c k s , n e w B l o c k T r a n s f o r m e r ) ; }

Slide 29

Slide 29 text

RESPONDING WITH PAGINATED ITEMS p u b l i c f u n c t i o n s h o w ( $ i d ) { $ b l o c k s = $ t h i s - > b l o c k - > f i n d ( $ i d ) ; r e t u r n $ t h i s - > r e s p o n s e - > p a g i n a t i o n ( $ b l o c k s , n e w B l o c k T r a n s f o r m e r ) ; }

Slide 30

Slide 30 text

OTHER RESPONSES / / R e s p o n d i n g W i t h N o C o n t e n t r e t u r n $ t h i s - > r e s p o n s e - > n o C o n t e n t ( ) ; / / R e s p o n d i n g W i t h C r e a t e d R e s p o n s e r e t u r n $ t h i s - > r e s p o n s e - > c r e a t e d ( ) ; / / A g e n e r i c e r r o r w i t h c u s t o m m e s s a g e a n d s t a t u s c o d e . r e t u r n $ t h i s - > r e s p o n s e - > e r r o r ( ' T h i s i s a n e r r o r . ' , 4 0 4 ) ; / / A n o t f o u n d e r r o r w i t h a n o p t i o n a l m e s s a g e a s t h e f i r s t p a r a m e t e r . r e t u r n $ t h i s - > r e s p o n s e - > e r r o r N o t F o u n d ( ) ; / / T h e r e a r e a l s o e r r o r B a d R e q u e s t , e r r o r F o r b i d d e n , e r r o r I n t e r n a l , e r r o r U n a u t h

Slide 31

Slide 31 text

Adding Additional Headers r e t u r n $ t h i s - > r e s p o n s e - > i t e m ( $ u s e r , n e w U s e r T r a n s f o r m e r ) - > w i t h H e a d e r ( ' X - F o o ' Adding Meta Data r e t u r n $ t h i s - > r e s p o n s e - > i t e m ( $ u s e r , n e w U s e r T r a n s f o r m e r ) - > a d d M e t a ( ' f o o ' / / s e t a n a r r a y o f m e t a d a t a i n s t e a d o f c h a i n i n g m u l t i p l e m e t h o d c a l l s r e t u r n $ t h i s - > r e s p o n s e - > i t e m ( $ u s e r , n e w U s e r T r a n s f o r m e r ) - > s e t M e t a ( $ m e t a Setting Response Status Code r e t u r n $ t h i s - > r e s p o n s e - > i t e m ( $ u s e r , n e w U s e r T r a n s f o r m e r ) - > s e t S t a t u s C o d e

Slide 32

Slide 32 text

TRANSFORMERS Easily and consistently transform objects into an array Type-cast integers and booleans, include pagination results, and nest relationships Fractal is the default transformation layer used by Dingo

Slide 33

Slide 33 text

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 - > a v a i l a b l e I n c l u d e s = [ ' p r e s e n t a t i o n s ' , ' b l o c k _ s e t t i n g s ' , ] ; $ t h i s - > d e f a u l t I n c l u d e s = [ ' b l o c k _ s e t t i n g s ' , ] ; } p u b l i c f u n c t i o n t r a n s f o r m ( B l o c k $ b l o c k ) { r e t u r n [ ' i d ' = > ( i n t ) $ b l o c k - > i d , ' n a m e ' = > $ b l o c k - > n a m e ,

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

FORM REQUEST END ERROR RESPONSES Extend the base API form request class Implement your own class Dingo\Api\Exception\ValidationHttpException should be thrown

Slide 37

Slide 37 text

AUTHENTICATION HTTP Basic (Dingo\Api\Auth\Provider\Basic) JSON Web Tokens (Dingo\Api\Auth\Provider\JWT) OAuth 2.0 (Dingo\Api\Auth\Provider\OAuth2) Custom Authentication Providers

Slide 38

Slide 38 text

DOCUMENTATION API Blueprint Documentation Annotate API controllers Generate documentation using the Artisan command But...

Slide 39

Slide 39 text

DREDD — HTTP API TESTING FRAMEWORK

Slide 40

Slide 40 text

“ Dredd is a language-agnostic command-line tool for validating API documentation written in API Blueprint format against its backend implementation. ” Dredd reads your API description Validates whether API replies with expected responses Continuous Integration Support Hooks — a glue code for each test setup and teardown Use of Gavel.js library Do not install dredd manually on Homestead - use a er.sh

Slide 41

Slide 41 text

HEADERS EXPECTATIONS All headers given in example must be present in the response Only values of headers significant for content negotiation are validated All other headers values can differ

Slide 42

Slide 42 text

BODY EXPECTATIONS All JSON keys on any level given in the example must be present in the response JSON Response JSON values must be of the same JSON primitive type All JSON values can differ Arrays can have additional items, type or structure is not validated. Plain text must match perfectly

Slide 43

Slide 43 text

PHP Dredd hook handler Provides a bridge between the Dredd API Testing Framework and PHP environment " r e q u i r e - d e v " : { " d d e l n a n o / d r e d d - h o o k s - p h p " : " ~ 1 . 0 . 0 " , }

Slide 44

Slide 44 text

HOOKS USAGE Loading db fixtures Cleanup a er test step or steps Handling authentication and sessions Passing data between transactions (saving state from responses to stash) Modifying request generated from blueprint Changing generated expectations Setting custom expectations Debugging via logging stuff

Slide 45

Slide 45 text

HOOKS TYPE beforeEach a erEach beforeAll a erAll before a er beforeEachValidationHooks a erEachValidationHooks

Slide 46

Slide 46 text

r e q u i r e _ _ D I R _ _ . ' / . . / . . / . . / v e n d o r / a u t o l o a d . p h p ' ; $ a p p = r e q u i r e _ _ D I R _ _ . ' / . . / . . / . . / b o o t s t r a p / a p p . p h p ' ; $ a p p - > m a k e ( \ I l l u m i n a t e \ C o n t r a c t s \ C o n s o l e \ K e r n e l : : c l a s s ) - > b o o t s t r a p ( ) ; A r t i s a n : : c a l l ( ' m i g r a t e ' ) ; $ u s e r = f a c t o r y ( \ E m a t e r i a l s \ A p i \ M o d e l s \ U s e r : : c l a s s ) - > c r e a t e ( [ ' e m a i l ' = > ' k n o w n u s e r @ e x a m p l e . d e v ' ] ) ; H o o k s : : b e f o r e E a c h ( f u n c t i o n ( & $ t r a n s a c t i o n ) u s e ( $ a p p ) { $ a p p - > m a k e ( ' d b ' ) - > b e g i n T r a n s a c t i o n ( ) ; } ) ; H o o k s : : a f t e r E a c h ( f u n c t i o n ( & $ t r a n s a c t i o n ) u s e ( $ a p p ) {

Slide 47

Slide 47 text

RUN DREDD d r e d d d o c u m e n t a t i o n . a p i b h t t p : / / l o c a l h o s t : 8 0 0 1 - - s e r v e r " p h p - S 0 . 0 . 0 . 0 : 8 0 0 1 - t p u b l i c / " - - l a n g u a g e v e n d o r / b i n / d r e d d - h o o k s - p h p - - h o o k f i l e s t e s t s / d r e d d / h o o k s / h o o k f i l e . p h p

Slide 48

Slide 48 text

REPOSITORIES " r e q u i r e " : { " b o s n a d e v / r e p o s i t o r i e s " : " 0 . * " } Container where data access logic is stored Hides the details of data access logic from business logic

Slide 49

Slide 49 text

i n t e r f a c e R e p o s i 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 a l l ( $ c o l u m n s = a r r a y ( ' * ' ) ) ; p u b l i c f u n c t i o n p a g i n a t e ( $ p e r P a g e = 1 5 , $ c o l u m n s = a r r a y ( ' * ' ) ) ; p u b l i c f u n c t i o n c r e a t e ( a r r a y $ d a t a ) ; p u b l i c f u n c t i o n u p d a t e ( a r r a y $ d a t a , $ i d ) ; p u b l i c f u n c t i o n d e l e t e ( $ i d ) ; p u b l i c f u n c t i o n f i n d ( $ i d , $ c o l u m n s = a r r a y ( ' * ' ) ) ; p u b l i c f u n c t i o n f i n d B y ( $ f i e l d , $ v a l u e , $ c o l u m n s = a r r a y ( ' * ' ) ) ; }

Slide 50

Slide 50 text

u s e A p p \ R e p o s i t o r i e s \ F i l m R e p o s i t o r y a s F i l m ; c l a s s F i l m s C o n t r o l l e r e x t e n d s C o n t r o l l e r { / * * * @ v a r F i l m * / p r i v a t e $ f i l m ; p u b l i c f u n c t i o n _ _ c o n s t r u c t ( F i l m $ f i l m ) { $ t h i s - > f i l m = $ f i l m ; } p u b l i c f u n c t i o n i n d e x ( ) { r e t u r n \ R e s p o n s e : : j s o n ( $ t h i s - > f i l m - > a l l ( ) ) ;

Slide 51

Slide 51 text

Basic actions are just enough for simple querying Added CriteriaInterface i n t e r f a c e C r i t e r i a I n t e r f a c e { p u b l i c f u n c t i o n s k i p C r i t e r i a ( $ s t a t u s = t r u e ) ; p u b l i c f u n c t i o n g e t C r i t e r i a ( ) ; p u b l i c f u n c t i o n g e t B y C r i t e r i a ( C r i t e r i a $ c r i t e r i a ) ; p u b l i c f u n c t i o n p u s h C r i t e r i a ( C r i t e r i a $ c r i t e r i a ) ; p u b l i c f u n c t i o n a p p l y C r i t e r i a ( ) ; }

Slide 52

Slide 52 text

c l a s s L e n g t h O v e r T w o H o u r s i m p l e m e n t s C r i t e r i a I n t e r f a c e { p u b l i c f u n c t i o n a p p l y ( $ m o d e l , R e p o s i t o r y $ r e p o s i t o r y ) { $ q u e r y = $ m o d e l - > w h e r e ( ' l e n g t h ' , ' > ' , 1 2 0 ) ; r e t u r n $ q u e r y ; } }

Slide 53

Slide 53 text

u s e A p p \ R e p o s i t o r i e s \ C r i t e r i a \ F i l m s \ L e n g t h O v e r T w o H o u r s ; u s e A p p \ R e p o s i t o r i e s \ F i l m R e p o s i t o r y a s F i l m ; c l a s s F i l m s C o n t r o l l e r e x t e n d s C o n t r o l l e r { / * * * @ v a r F i l m * / p r i v a t e $ f i l m ; p u b l i c f u n c t i o n _ _ c o n s t r u c t ( F i l m $ f i l m ) { $ t h i s - > f i l m = $ f i l m ; } p u b l i c f u n c t i o n i n d e x ( ) {

Slide 54

Slide 54 text

CORS (CROSS-ORIGIN RESOURCE SHARING) " r e q u i r e " : { " b a r r y v d h / l a r a v e l - c o r s " : " ^ 0 . 7 . 2 " } Allows you to send CORS headers with ACL-style per-url configuration. Supports Laravel & Lumen

Slide 55

Slide 55 text

RESOURCES - - - Laravel documentation Why choose Laravel Using Repository