Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Asyncio Stack & React.js or Development on the Edge

Asyncio Stack & React.js or Development on the Edge

Slides from my EuroPython 2015 talk about developing modern web applications with React.js on frontend and Python 3 Asyncio stack on backend

Igor Davydenko

July 20, 2015
Tweet

More Decks by Igor Davydenko

Other Decks in Programming

Transcript

  1. I am... Igor Davydenko Python & React.js developer From Kyiv,

    Ukraine Works on Ezhome Inc. Primarly designs & develops backend API Personal Site @ GitHub @ Twitter
  2. My Path Everything started from Microsoft FrontPage, early 2002 Met

    PHP4, HTML4, early 2003 First school projects, sites, 2003-2005 First work, 2006 Met PHP5, late 2006 Own web design studio, 2007 Switch to Python & Django, late 2007
  3. My Path Outsorcing career, 2008-2011 Django, Django, Django oDesk PS,

    2011-2012 Django is good, but Flask is better GetGoing Inc., 2012-2015 Flask, Flask, Flask. Oh no, Django again Ezhome Inc., early 2015 Django REST Framework, okay
  4. In Total Python developer for past 8 years Using Django

    from 0.96 Using Flask from 0.7 Still not satisfied …
  5. JavaScript was bad Prototype was big and hard jQuery was

    small and easy. Somewhen, decades ago jQuery UI :( jQuery plugins :( :(
  6. JavaScript was bad My motto was: Let someone else make

    frontend Tasks Backbone? Okay, but not in big teams Angular? No, no, no. Just no Vanilla JS? Cool, but not in big teams
  7. JavaScript problems No standart modules < s c r i

    p t > -hell in templates Hard to maintain across distributed team One developer -> one code style, X developers -> X code styles Hard to maintain between projects Same v e n d o r / directories, no dependencies management
  8. But then... node.js happens npm installs dependencies CommonJS allows reuse

    your code browserify builds bundles from your code jshint/jslint/jsrc lints your code Even some people starts write backends in node.js
  9. Before In template.html, < s c r i p t

    s r c = " / p a t h / t o / u n d e r s c o r e . j s " t y p e = " t e x t / j a v a s c r i p t " > < / s c r i p t > < s c r i p t t y p e = " t e x t / j a v a s c r i p t " > _ . e a c h ( d o c u m e n t . g e t E l e m e n t s B y T a g N a m e ( " a " ) , f u n c t i o n ( i t e m ) { i f ( i t e m . h r e f . i n d e x O f ( " h t t p : / / " ) | | i t e m . h r e f . i n d e x O f ( " h t t p s : / / " ) ) { i t e m . h r e f = " / g o ? " + i t e m . h r e f ; i t e m . o n c l i c k = f u n c t i o n ( ) { i t e m . c l a s s L i s t . a d d ( " v i s i t e d - l i n k " ) ; r e t u r n F a l s e ; } } } ) ; . . . < / s c r i p t >
  10. Now In template.html, < s c r i p t

    s r c = " / p a t h / t o / b u n d l e . j s " t y p e = " t e x t / j a v a s c r i p t " > < / s c r i p t > < s c r i p t t y p e = " t e x t / j a v a s c r i p t " > p r o c e s s E x t e r n a l L i n k s ( d o c u m e n t . g e t E l e m e n t s B y T a g N a m e ( " a " ) ) ; < / s c r i p t >
  11. Now In js/external-links.js, i m p o r t {

    e a c h } f r o m " u n d e r s c o r e " ; f u n c t i o n h a n d l e E x t e r n a l L i n k C l i c k ( e v t ) { e v t . p r e v e n t D e f a u l t ( ) ; e v t . t a r g e t . c l a s s L i s t . a l l ( " v i s i t e d - l i n k " ) ; } e x p o r t f u n c t i o n p r o c e s s E x t e r n a l L i n k s ( e l e m e n t s ) { e a c h ( e l e m e n t s , i t e m = > { i f ( / ^ h t t p s ? \ : \ / \ / / . t e s t ( i t e m . h r e f ) ) { i t e m . h r e f = " / g o ? " + i t e m . h r e f ; i t e m . a d d E v e n t L i s t e n e r ( " c l i c k " , h a n d l e E x t e r a n l L i n k C l i c k ) ; } } ) ; } e x p o r t d e f a u l t { p r o c e s s E x t e r n a l L i n k s : p r o c e s s E x t e r n a l L i n k s } ;
  12. ES2015. Modules ./lib/myLibrary.js e x p o r t f

    u n c t i o n m y F u n c t i o n ( ) { . . . } e x p o r t d e f a u l t { m y F u n c t i o n : m y F u n c t i o n } ; ./app.js i m p o r t m y L i b r a r y f r o m " . / l i b / m y L i b r a r y " ; i m p o r t { m y F u n c t i o n } f r o m " . / l i b / m y L i b r a r y " ;
  13. ES2015. Let + Const c o n s t u

    n c h a n g a b l e = t r u e ; l e t c h a n g e a b l e ; c h a n g e a b l e = t r u e ; u n c h a n g e a b l e = f a l s e ; / / E r r o r
  14. ES2015. Arrows c o n s t e p i

    s o d e s = [ . . . ] ; c o n s t a N e w H o p e = e p i s o d e s . f i l t e r ( i t e m = > i t e m . e p i s o d e = = = " I V " ) ; c o n s t e p i s o d e T i t l e s = e p i s o d e s . m a p ( i t e m = > { r e t u r n i t e m . t i t l e . t o U p p e r C a s e ( ) ; } )
  15. ES2015. Classes c l a s s A N e

    w H o p e e x t e n d s E p i s o d e { i d : " I V " , n a m e : " A N e w H o p e " , c o n s t r u c t o r ( ) { s u p e r ( ) ; t h i s . d i r e c t e d B y = " G e o r g e L u c a s " ; } r e n d e r ( ) { . . . } } c o n s t a N e w H o p e = n e w A N e w H o p e ( ) ;
  16. ES2015. Template Strings c o n s t e p

    i s o d e = ' I V ' ; c o n s t t i t l e = ' A N e w H o p e ' ; ` A l o n g t i m e a g o i n a g a l a x y f a r , f a r a w a y . . . S T A R W A R S E p i s o d e $ { e p i s o d e } $ { t i t l e . t o U p p e r C a s e ( ) } I t i s a p e r i o d o f c i v i l w a r . R e b e l s p a c e s h i p s , s t r i k i n g f r o m a h i d d e n b a s e , h a v e w o n t h e i r f i r s t v i c t o r y a g a i n s t t h e e v i l G a l a c t i c E m p i r e . `
  17. ES2015. Destructing c o n s t [ f i

    r s t , , t h i r d ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] ; c o n s t { e p i s o d e , t i t l e } = { e p i s o d e : " I V " , t i t l e : " A N e w H o p e " , o p e n i n g : " . . . " } ; c o n s t { e p i s o d e : i d , t i t l e : n a m e } = { . . . } ;
  18. ES2015. Map + Set v a r m a p

    p i n g = n e w M a p ( ) ; m a p . s e t ( " I V " , " A N e w H o p e " ) ; m a p . g e t ( " I V " ) = = = " A N e w H o p e " ; v a r e p i s o d e s = n e w S e t ( ) ; e p i s o d e s . a d d ( " A N e w H o p e " ) . a d d ( " T h e E m p i r e S t r i k e s B a c k " ) . a d d ( " R e t u r n o f t h e J e d i " ) . a d d ( " A N e w H o p e " ) ; e p i s o d e s . h a s ( " A N e w H o p e " ) ; e p i s o d e s . s i z e = = = 3 ;
  19. And More Learn ES2015 Default + Rest + Spread Iterators

    + For..Of Generators Improved Unicode Module Loaders Proxies Symbols ...
  20. How to Use? Use Babel for all good things! Supports

    browserify, webpack, ... Emerges eslint as your one and only JS linter
  21. React.js. A Simple Component i m p o r t

    R e a c t , { C o m p o n e n t } f r o m " r e a c t " ; c l a s s E u r o P y t h o n e x t e n d s C o m p o n e n t { r e n d e r ( ) { r e t u r n ( ; } } R e a c t . r e n d e r ( < d i v > H e l l o , E u r o P y t h o n 2 0 1 5 ! < / d i v > ) < E u r o P y t h o n / > , d o c u m e n t . g e t E l e m e n t B y I d ( " r e a c t - c o n t a i n e r " ) ) ;
  22. React.js. A Stateful Component c l a s s E

    u r o P y t h o n e x t e n d s C o m p o n e n t { s t a t e = { c l i c k s : 0 } , h a n d l e C l i c k = ( ) = > { t h i s . s e t S t a t e ( { c l i c k s : t h i s . s t a t e . c l i c k s + 1 } ) ; } , r e n d e r ( ) { c o n s t { c l i c k s } = t h i s . s t a t e ; r e t u r n ( } } R e a c t . r e n d e r ( < d i v > T h i s b u t t o n c l i c k e d { c l i c k s } t i m e ( s ) . < b r / > < b u t t o n o n C l i c k = { t h i s . h a n d l e C l i c k } > C l i c k M e < / b u t t o n > < / d i v > ) < E u r o P y t h o n / > , d o c u m e n t . g e t E l e m e n t B y I d ( " r e a c t - c o n t a i n e r " ) ) ;
  23. React.js. Using Components i m p o r t M

    a r k d o w n f r o m " . / c o m p o n e n t s / M a r k d o w n " ; c l a s s C o m m e n t F o r m e x t e n d s C o m p o n e n t { s t a t e = { c o m m e n t : " " , p r e v i e w : f a l s e } , h a n d l e C o m m e n t C h a n g e = ( e v t ) = > { t h i s . s e t S t a t e ( { c o m m e n t : e v t . t a r g e t . v a l u e } ) ; } , h a n d l e P r e v i e w C l i c k = ( e v t ) = > { t h i s . s e t S t a t e ( { p r e v i e w : t r u e } ) ; } , r e n d e r ( ) { c o n s t { c o m m e n t , p r e v i e w } = t h i s . s t a t e ; i f ( p r e v i e w ) r e t u r n r e t u r n ( ; } } < M a r k d o w n > { c o m m e n t } < / M a r k d o w n > ; < d i v > < t e x t a r e a o n C h a n g e = { t h i s . h a n d l e C o m m e n t C h a n g e } p l a c e h o l d e r = " Y o u r C o m m e n t " v a l u e = { c o m m e n t } / > < b u t t o n o n C l i c k = { t h i s . h a n d l e P r e v i e w C l i c k } > P r e v i e w < / b u t t o n > < / d i v > )
  24. React.js. Fetching data c l a s s C o

    m m e n t s e x t e n d s C o m p o n e n t { s t a t e = { d a t a : [ ] , s t a t u s : n u l l } , c o m p o n e n t D i d M o u n t ( ) { t h i s . l o a d D a t a ( ) ; } , l o a d D a t a = ( ) = > { f e t c h ( a p i U r l ) . t h e n ( r e s p o n s e = > { i f ( r e s p o n s e . o k ( ) ) { r e t u r n P r o m i s e . r e s o l v e ( r e s p o n s e . j s o n ( ) ) ; } r e t u r n P r o m i s e . r e j e c t ( n e w E r r o r ( r e s p o n s e . s t a t u s T e x t | | r e s p o n s e . s t a t u s ) ) ; } ) . t h e n ( j s o n = > { t h i s . s e t S t a t e ( { d a t a : j s o n , s t a t u s : t r u e } ) ; } , ( ) = > { t h i s . s e t S t a t e ( { d a t a : [ ] , s t a t u s : f a l s e } ) ; } ) ) ; } , . . .
  25. React.js. Fetching data . . . r e n d

    e r ( ) { c o n s t { d a t a , s t a t u s } = t h i s . s t a t e ; i f ( s t a t u s = = = n u l l ) { . . . / / L o a d i n g } e l s e i f ( s t a t u s = = = f a l s e ) { . . . / / S e r v e r e r r o r } e l s e i f ( ! d a t a . l e n g t h ) { . . . / / E m p t y d a t a } e l s e { . . . / / V a l i d d a t a } } }
  26. React.js. One-way data binding c l a s s C

    o m m e n t s e x t e n d s C o m p o n e n t { . . . r e n d e r ( ) { c o n s t c o n t e n t = t h i s . s t a t e . d a t a . m a p ( i t e m = > ( ) ; } } c l a s s C o m m e n t e x t e n d s C o m p o n e n t { s t a t i c d e f a u l t P r o p s = { d a t a : { } } , p r o p T y p e s = { d a t a : P r o p T y p e s . s h a p e ( { . . . } ) } , r e n d e r ( ) { r e t u r n ( . . . ) } } < C o m m e n t d a t a = { i t e m } k e y = { " c o m m e n t - " + i t e m . i d } / > )
  27. React.js. One-way data binding Comments is Higher Order Component Comment

    is Dumb Component Higher Order Components Data loading Events handling Dumb Components Set of reusable Components Shareable across one and many projects
  28. And More React DOM is separate package from 0.14 React

    Native, React Canvas Routing via react-router Reusable Components react-bootstrap react-dnd Flux Relay GraphQL
  29. asyncio Asynchronous I/O, event loop, coroutines, and tasks https://docs.python.org/3/library/asyncio.html i

    m p o r t a s y n c i o @ a s y n c i o . c o r o u t i n e d e f h e l l o ( ) : r e t u r n " H e l l o , w o r l d ! " l o o p = a s y n c i o . g e t _ e v e n t _ l o o p ( ) c o n t e n t = l o o p . r u n _ u n t i l _ c o m p l e t e ( h e l l o ( ) ) p r i n t ( c o n t e n t ) l o o p . c l o s e ( ) Included in Python 3.4 and later Available in Python 3.3 with $ p i p i n s t a l l a s y n c i o Backported to Python 2.7 as trollius (I don't recommend to use it anyway)
  30. aiohttp HTTP client/server for asyncio Latest version: 0 . 1

    6 . 5 http://aiohttp.readthedocs.org/ i m p o r t a s y n c i o i m p o r t a i o h t t p @ a s y n c i o . c o r o u t i n e d e f f e t c h _ p a g e ( u r l ) : r e s p o n s e = y i e l d f r o m a i o h t t p . r e q u e s t ( ' G E T ' , u r l ) a s s e r t r e s p o n s e . s t a t u s = = 2 0 0 r e t u r n ( y i e l d f r o m r e s p o n s e . r e a d ( ) ) l o o p = a s y n c i o . g e t _ e v e n t _ l o o p ( ) c o n t e n t = l o o p . r u n _ u n t i l _ c o m p l e t e ( f e t c h _ p a g e ( ' h t t p : / / e p 2 0 1 5 . e u r o p y t h o n . e u / ' ) ) p r i n t ( c o n t e n t ) l o o p . c l o s e ( )
  31. aiohttp.web Web framework for asyncio http://aiohttp.readthedocs.org/en/v0.16.5/web.html i m p o

    r t a s y n c i o f r o m a i o h t t p i m p o r t w e b @ a s y n c i o . c o r o u t i n e d e f h e l l o ( r e q u e s t ) : r e t u r n w e b . R e s p o n s e ( b o d y = ' H e l l o , w o r l d ! ' , c o n t e n t _ t y p e = ' t e x t / p l a i n ' ) a p p = w e b . A p p l i c a t i o n ( ) a p p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / ' , h e l l o ) $ g u n i c o r n - k a i o h t t p . w o r k e r . G u n i c o r n W e b W o r k e r - w 9 - t 6 0 a p p : a p p
  32. aiopg Accessing PostgreSQL database from the asyncio Latest version: 0

    . 7 . 0 http://aiopg.readthedocs.org/ i m p o r t a s y n c i o f r o m a i o p g i m p o r t c r e a t e _ p o o l @ a s y n c i o . c o r o u t i n e d e f h e l l o ( d s n ) : p o o l = y i e l d f r o m c r e a t e _ p o o l ( d s n ) w i t h ( y i e l d f r o m p o o l . c u r s o r ( ) ) a s c u r s o r : y i e l d f r o m c u r s o r . e x e c u t e ( ' S E L E C T 1 ' ) s e l e c t e d = y i e l d f r o m c u r s o r . f e t c h o n e ( ) a s s e r t s e l e c t e d = = ( 1 , ) l o o p = a s y n c i o . g e t _ e v e n t _ l o o p ( ) l o o p . r u n _ u n t i l _ c o m p l e t e ( h e l l o ( ' d b n a m e = a i o p g u s e r = . . . p a s s w o r d = . . . h o s t = . . . ' ) ) l o o p . c l o s e ( )
  33. aioredis / asyncio_redis Accessing Redis datasotre from the asyncio a

    i o r e d i s from a i o - l i b s Latest version: 0 . 1 . 5 http://aioredis.readthedocs.org/ a s y n c i o _ r e d i s from third-party developers Latest version: 0 . 1 3 . 4 http://asyncio-redis.readthedocs.org/
  34. And many others Python Asyncio Resources MySQL: aiomysql Mongo: asyncio_mongo

    CouchDB: aiocouchdb ElasticSearch: aioes Memcached: aiomcache AMQP: aioamqp ØMQ: aiozmq
  35. And many others All Asyncio projects @ PyPI S3: aio-s3

    SSH: asyncssh Autobahn, WebSocket & WAMP RxPY, Reactive Extensions for Python Pulsar, Concurrent framework for Python
  36. Architecture All starts from view functions (handlers) View functions should

    be a coroutine, and return w e b . R e s p o n s e i m p o r t a s y n c i o f r o m a i o h t t p i m p o r t w e b @ a s y n c i o . c o r o u t i n e d e f i n d e x ( r e q u e s t ) : r e t u r n w e b . R e s p o n s e ( b o d y = ' H e l l o , w o r l d ! ' , c o n t e n t _ t y p e = ' t e x t / p l a i n ' ) It's good idea to put all view functions to v i e w s . p y module
  37. Architecture Next you need to create an w e b

    . A p p l i c a t i o n And register handler for a request f r o m a i o h t t p i m p o r t w e b f r o m . i m p o r t v i e w s a p p = w e b . A p p l i c a t i o n ( ) a p p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / ' , v i e w s . i n d e x ) Obvious to put application code to a p p . p y module
  38. Architecture Now you ready to serve your application I recommend

    to use Gunicorn $ g u n i c o r n - b 0 . 0 . 0 . 0 : 8 0 0 0 - k a i o h t t p . w o r k e r . G u n i c o r n W e b W o r k e r - w 9 - t 6 0 p r o j e c t . a p p : a p p Add - - r e l o a d flag to automatically reload Gunicorn server on code change
  39. Handling GET/POST data In views.py, @ a s y n

    c i o . c o r o u t i n e d e f s e a r c h ( r e q u e s t ) : " " " S e a r c h b y q u e r y f r o m G E T p a r a m s . " " " q u e r y = r e q u e s t . G E T [ ' q u e r y ' ] l o c a l e = r e q u e s t . G E T . g e t ( ' l o c a l e ' , ' u k _ U A ' ) . . . r e t u r n w e b . R e s p o n s e ( . . . )
  40. Handling GET/POST data In views.py, @ a s y n

    c i o . c o r o u t i n e d e f s u b m i t ( r e q u e s t ) : " " " S u b m i t f o r m P O S T d a t a . " " " d a t a = y i e l d f r o m r e q u e s t . p o s t ( ) # N o w P O S T d a t a a v a i l a b l e a s ` ` r e q u e s t . P O S T ` ` . . . r e t u r n w e b . R e s p o n s e ( . . . )
  41. Handling GET/POST data In app.py, a p p . r

    o u t e r . a d d _ r o u t e ( ' G E T ' , ' / s e a r c h ' , v i e w s . s e a r c h ) a p p . r o u t e r . a d d _ r o u t e ( ' P O S T ' , ' / s u b m i t ' , v i e w s . s u b m i t )
  42. Handling variable routes In views.py, @ a s y n

    c i o . c o r o u t i n e d e f p r o j e c t ( r e q u e s t ) : p r o j e c t _ i d = r e q u e s t . m a t c h _ i n f o [ ' p r o j e c t _ i d ' ] . . . r e t u r n w e b . R e s p o n s e ( . . . )
  43. Handling variable routes In app.py, a p p . r

    o u t e r . a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t s / { p r o j e c t _ i d } ' , v i e w s . p r o j e c t ) Or even, a p p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t s / { p r o j e c t _ i d : \ d + } ' , v i e w s . p r o j e c t )
  44. Named routes, reverse constructing, and redirect In app.py, a p

    p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t s ' , v i e w s . p r o j e c t s , n a m e = ' p r o j e c t s ' ) a p p . r o u t e r . a d d _ r o u t e ( ' P O S T ' , ' / p r o j e c t s ' , v i e w s . a d d _ p r o j e c t )
  45. Named routes, reverse constructing, and redirect In views.py, @ a

    s y n c i o . c o r o u t i n e d e f a d d _ p r o j e c t ( r e q u e s t ) : d a t a = y i e l d f r o m r e q u e s t . p o s t ( ) . . . u r l = r e q u e s t . a p p . r o u t e r [ ' p r o j e c t s ' ] . u r l ( ) r e t u r n w e b . H T T P F o u n d ( u r l ) @ a s y n c i o . c o r o u t i n e d e f p r o j e c t s ( r e q u e s t ) : . . .
  46. You don't need to f r o m a p

    p i m p o r t a p p Or f r o m f l a s k i m p o r t c u r r e n t _ a p p either Request contains a p p instance for all your needs In app.py, f r o m . i m p o r t s e t t i n g s . . . a p p [ ' s e t t i n g s ' ] = s e t t i n g s
  47. You don't need to f r o m a p

    p i m p o r t a p p In views.py, @ a s y n c i o . c o r o u t i n e d e f s e a r c h ( r e q u e s t ) : s e t t i n g s = r e q u e s t . a p p [ ' s e t t i n g s ' ] q u e r y = r e q u e s t . G E T [ ' q u e r y ' ] l o c a l e = r e q u e s t . G E T . g e t ( ' l o c a l e ' , s e t t i n g s . D E F A U L T _ L O C A L E ) . . . r e t u r n w e b . R e s p o n s e ( . . . )
  48. Middlewares w e b . A p p l i

    c a t i o n accepts optional middlewares factories sequence Middleware Factory should be a coroutine and returns a coroutine In app.py, @ a s y n c i o . c o r o u t i n e d e f t r i v i a l _ m i d d l e w a r e ( a p p , h a n d l e r ) : @ a s y n c i o . c o r o u t i n e d e f m i d d l e w a r e ( r e q u e s t ) : r e t u r n ( y i e l d f r o m h a n d l e r ( r e q u e s t ) ) r e t u r n m i d d l e w a r e . . . a p p = w e b . A p p l i c a t i o n ( m i d d l e w a r e s = [ t r i v i a l _ m i d d l e w a r e ] )
  49. Middlewares Ready to use Middlewares User Sessions, a i o

    h t t p _ s e s s i o n Debug Toolbar, a i o h t t p _ d e b u g t o o l b a r In app.py, i m p o r t a i o h t t p _ d e b u g t o o l b a r f r o m a i o h t t p _ d e b u g t o o l b a r i m p o r t t o o l b a r _ m i d d l e w a r e _ f a c t o r y f r o m a i o h t t p _ s e s s i o n i m p o r t s e s s i o n _ m i d d l e w a r e f r o m a i o h t t p _ s e s s i o n . c o o k i e _ s t o r a g e i m p o r t E n c r y p t e d C o o k i e S t o r a g e a p p = w e b . A p p l i c a t i o n ( m i d d l e w a r e s = [ t o o l b a r _ m i d d l e w a r e _ f a c t o r y , s e s s i o n _ m i d d l e w a r e ( E n c r y p t e d C o o k i e S t o r a g e ( b ' 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 ' ) ) ] ) a i o h t t p _ d e b u g t o o l b a r . s e t u p ( a p p )
  50. Middlewares Handling Exceptions In app.py, @ a s y n

    c i o . c o r o u t i n e d e f e r r o r h a n d l e r _ m i d d l e w a r e ( a p p , h a n d l e r ) : @ a s y n c i o . c o r o u t i n e d e f m i d d l e w a r e ( r e q u e s t ) : t r y : r e t u r n ( y i e l d f r o m h a n d l e r ( r e q u e s t ) ) e x c e p t w e b . H T T P E r r o r a s e r r : # A s i t s p e c i a l c a s e w e c o u l d p a s s ` ` e r r ` ` a s s e c o n d a r g u m e n t t o # e r r o r h a n d l e r r e t u r n ( y i e l d f r o m v i e w s . e r r o r ( r e q u e s t , e r r ) ) r e t u r n m i d d l e w a r e
  51. User Sessions aiohttp_session Latest version: 0 . 1 . 1

    Supports storing session data in encrypted cookie or redis Enabled by passing s e s s i o n _ m i d d l e w a r e to middleware factories sequence In views.py, f r o m a i o h t t p _ s e s s i o n i m p o r t g e t _ s e s s i o n @ a s y n c i o . c o r o u t i n e d e f l o g i n ( r e q u e s t ) : . . . s e s s i o n = y i e l d f r o m g e t _ s e s s i o n ( r e q u e s t ) s e s s i o n [ ' u s e r _ i d ' ] = u s e r _ i d r e t u r n w e b . R e s p o n s e ( . . . )
  52. Rendering Templates Jinja2 & Mako supported via aiohttp_jinja2 & aiohttp_mako

    Jinja2 Support In app.py, i m p o r t a i o h t t p _ j i n j a 2 i m p o r t j i n j a 2 . . . a i o h t t p _ j i n j a 2 . s e t u p ( a p p , l o a d e r = j i n j a 2 . F i l e S y s t e m L o a d e r ( ' / p a t h / t o / t e m p l a t e s ' ) )
  53. Rendering Templates Jinja2 Support In views.py, i m p o

    r t a i o h t t p _ j i n j a 2 @ a i o h t t p _ j i n j a 2 . t e m p l a t e ( ' i n d e x . h t m l ' ) d e f i n d e x ( r e q u e s t ) : r e t u r n { ' i s _ i n d e x ' : T r u e }
  54. Rendering Templates Jinja2 Support In views.py, f r o m

    a i o h t t p _ j i n j a 2 i m p o r t r e n d e r _ t e m p l a t e @ a s y n c i o . c o r o u t i n e d e f i n d e x ( r e q u e s t ) : r e t u r n r e n d e r _ t e m p l a t e ( ' i n d e x . h t m l ' , r e q u e s t , { ' i s _ i n d e x ' : T r u e } )
  55. Rendering JSON In utils.py, i m p o r t

    u j s o n f r o m a i o h t t p i m p o r t w e b d e f j s o n _ r e s p o n s e ( d a t a , * * k w a r g s ) : # S o m e t i m e s u s e r n e e d s t o o v e r r i d e d e f a u l t c o n t e n t t y p e f o r J S O N k w a r g s . s e t d e f a u l 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 ' ) r e t u r n w e b . R e s p o n s e ( u j s o n . d u m p s ( d a t a ) , * * k w a r g s ) Note: I recommend to use ujson for work with JSON data in Python, cause of speed.
  56. Rendering JSON In views.py, f r o m . u

    t i l s i m p o r t j s o n _ r e s p o n s e @ a s y n c i o . c o r o u t i n e d e f a p i _ b r o w s e r ( r e q u e s t ) : r e t u r n j s o n _ r e s p o n s e ( { ' p r o j e c t s _ u r l ' : r e q u e s t . a p p . r o u t e r [ ' p r o j e c t s ' ] . u r l ( ) , } )
  57. Serving Static Files Important: It's highly recommend to use nginx,

    Apache, or other web server for serving static files in production. In app.py, a p p . r o u t e r . a d d _ s t a t i c ( ' / s t a t i c ' , ' / p a t h / t o / s t a t i c ' , n a m e = ' s t a t i c ' )
  58. Serving Static Files In views.py, @ a i o h

    t t p _ j i n j a 2 . t e m p l a t e ( ' i n d e x . h t m l ' ) d e f i n d e x ( r e q u e s t ) : r e t u r n { ' a p p ' : r e q u e s t . a p p , ' i s _ i n d e x ' : T r u e }
  59. Serving Static Files In index.html, < s c r i

    p t s r c = " { { a p p . r o u t e r . s t a t i c . u r l ( f i l e n a m e = " d i s t / j s / p r o j e c t . j s " ) } } " t y p e = " t e x t / j a v a s c r i p t " > < / s c r i p t >
  60. And More WebSockets Expect Header Custom Conditions for Routes Lookup

    Class Based Handlers And I say it again, WebSockets
  61. Add Route Context Manager f r o m c o

    n t e x t l i b i m p o r t c o n t e x t m a n a g e r @ c o n t e x t m a n a g e r d e f a d d _ r o u t e _ c o n t e x t ( a p p , v i e w s , u r l _ p r e f i x = N o n e , n a m e _ p r e f i x = N o n e ) : d e f a d d _ r o u t e ( m e t h o d , u r l , n a m e ) : v i e w = g e t a t t r ( v i e w s , n a m e ) u r l = ( ' / ' . j o i n ( ( u r l _ p r e f i x . r s t r i p ( ' / ' ) , u r l . l s t r i p ( ' / ' ) ) ) i f u r l _ p r e f i x e l s e u r l ) n a m e = ' . ' . j o i n ( ( n a m e _ p r e f i x , n a m e ) ) i f n a m e _ p r e f i x e l s e n a m e r e t u r n a p p . r o u t e r . a d d _ r o u t e ( m e t h o d , u r l , v i e w , n a m e = n a m e ) r e t u r n a d d _ r o u t e
  62. Add Route Context Manager In app.py, f r o m

    . a p i i m p o r t v i e w s a s a p i _ v i e w s w i t h a d d _ r o u t e _ c o n t e x t ( a p p , a p i _ v i e w s , ' / a p i ' , ' a p i ' ) a s a d d _ r o u t e : a d d _ r o u t e ( ' G E T ' , ' / ' , ' i n d e x ' ) a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t s ' , ' p r o j e c t s ' ) a d d _ r o u t e ( ' P O S T ' , ' / p r o j e c t s ' , ' a d d _ p r o j e c t ' ) a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t / { p r o j e c t _ i d : \ d + } ' , ' p r o j e c t ' ) a d d _ r o u t e ( ' P U T ' , ' / p r o j e c t / { p r o j e c t _ i d : \ d + } ' , ' e d i t _ p r o j e c t ' ) a d d _ r o u t e ( ' D E L E T E ' , ' / p r o j e c t / { p r o j e c t _ i d : \ d + } ' , ' d e l e t e _ p r o j e c t ' )
  63. Add Route Context Manager In api/views.py, i m p o

    r t a s y n c i o f r o m . . u t i l s i m p o r t j s o n _ r e s p o n s e @ a s y n c i o . c o r o u t i n e d e f i n d e x ( r e q u e s t ) : r o u t e r = r e q u e s t . a p p . r o u t e r p r o j e c t _ u r l = r o u t e r [ ' a p i . p r o e j c t ' ] . u r l ( p a r t s = { ' p r o j e c t _ i d ' : 4 2 } ) p r o j e c t _ u r l = p r o j e c t _ u r l . r e p l a c e ( ' 4 2 ' , ' { p r o j e c t _ i d } ' ) r e t u r n j s o n _ r e s p o n s e ( { ' u r l s ' : { ' a d d _ p r o j e c t ' : r o u t e r [ ' a p i . a d d _ p r o j e c t ' ] . u r l ( ) , ' p r o j e c t ' : p r o j e c t _ u r l , ' p r o j e c t s ' : r o u t e r [ ' a p i . p r o j e c t s ' ] . u r l ( ) , } } )
  64. Immutable Settings Python 3.3+ has M a p p i

    n g T y p e P r o x y Settings shouldn't be changed across the app Welcome, rororo.settings In app.py, f r o m r o r o r o . s e t t i n g s i m p o r t i m m u t a b l e _ s e t t i n g s f r o m . i m p o r t s e t t i n g s d e f c r e a t e _ a p p ( * * o p t i o n s ) : s e t t i n g s _ d i c t = i m m u t a b l e _ s e t t i n g s ( s e t t i n g s , * * o p t i o n s ) a p p = w e b . A p p l i c a t i o n ( ) a p p [ ' s e t t i n g s ' ] = s e t t i n g s _ d i c t . . . r e t u r n a p p
  65. Other Settings & Logging Helpers rororo.settings i n j e

    c t _ s e t t i n g s s e t u p _ l o c a l e s e t u p _ l o g g i n g s e t u p _ t i m e z o m e t o _ b o o l rororo.logger d e f a u l t _ l o g g i n g _ d i c t u p d a t e _ s e n t r y _ l o g g i n g
  66. Supports DEBUG Mode from Settings c l a s s

    A p p l i c a t i o n ( w e b . A p p l i c a t i o n ) : d e f _ _ i n i t _ _ ( s e l f , * * k w a r g s ) : s e l f [ ' s e t t i n g s ' ] = k w a r g s . p o p ( ' s e t t i n g s ' ) s u p e r ( ) . _ _ i n i t _ _ ( * * k w a r g s ) d e f m a k e _ h a n d l e r ( s e l f , * * k w a r g s ) : k w a r g s [ ' d e b u g ' ] = s e l f [ ' s e t t i n g s ' ] [ ' D E B U G ' ] k w a r g s [ ' l o o p ' ] = s e l f . l o o p r e t u r n s e l f . _ h a n d l e r _ f a c t o r y ( s e l f , s e l f . r o u t e r , * * k w a r g s )
  67. Schemas You need to validate request & response data Use

    JSON Schema for validation Describe Schemas with jsl Welcome, rororo.schemas In api/views.py, f r o m r o r o r o . s c h e m a s i m p o r t S c h e m a f r o m . i m p o r t s c h e m a s @ a s y n c i o . c o r o u t i n e d e f a d d _ p r o j e c t ( r e q u e s t ) : s c h e m a = S c h e m a ( s c h e m a s . a d d _ p r o j e c t , r e s p o n s e _ f a c t o r y = j s o n _ r e s p o n s e ) d a t a = s c h e m a . v a l i d a t e _ r e q u e s t ( ( y i e l d f r o m r e q u e s t . p o s t ( ) ) ) . . . r e t u r n s c h e m a . m a k e _ r e s p o n s e ( p r o j e c t _ d i c t )
  68. Schemas Describing Schemas In api/schemas/add_project.py, f r o m j

    s l i m p o r t D o c u m e n t , I n t e g e r F i e l d , S t r i n g F i e l d c l a s s P r o j e c t ( D o c u m e n t ) : n a m e = S t r i n g F i e l d ( m i n _ l e n g t h = 1 , m a x _ l e n g t h = 3 2 , r e q u i r e d = T r u e ) s l u g = S t r i n g F i e l d ( m i n _ l e n g t h = 1 , m a x _ l e n g t h = 3 2 , r e q u i r e d = T r u e ) d e s c r i p t i o n = S t r i n g F i e l d ( m a x _ l e n g t h = 2 5 5 ) c l a s s R e s p o n s e ( P r o j e c t ) : i d = I n t e g e r F i e l d ( m i n i m u m = 0 , r e q u i r e d = T r u e ) r e q u e s t = P r o j e c t . g e t _ s c h e m a ( ) r e s p o n s e = R e s p o n s e . g e t _ s c h e m a ( ) Or use plain Python dicts instead
  69. Schemas Describing Schemas In api/schemas/__init__.py, f r o m .

    i m p o r t a d d _ p r o j e c t # n o q a
  70. JavaScript is quite good right now ES2015 is a great

    step in right direction Many tools around JS is maturing too Bundling is easy, meet webpack Linting is easy, meet eslint Making UI is easy, meet react And I still not talking about DX tools :)
  71. Asyncio Stack is ready for usage The Future is Here!

    Use Python 3.4 for all good things a i o h t t p . w e b , easy to start and easy to use a i o p g . s a allows you to forget about ORM r o r o r o contains useful helpers for a i o h t t p . w e b apps If you miss something, port it to Asyncio stack by yourself Don't forget to payback to Open Source Software
  72. Bonus. Python 3.5 a s y n c d e

    f l o g o u t ( r e q u e s t ) : s e s s i o n = a w a i t g e t _ s e s s i o n ( r e q u e s t ) s e s s i o n . i n v a l i d a t e ( ) r e t u r n R e s p o n s e ( s t a t u s = 2 0 4 ) a s y n c d e f p r o j e c t s ( r e q u e s t ) : p r o j e c t s = [ ] a s y n c w i t h c r e a t e _ e n g i n e ( D S N ) a s c o n n : q u e r y = . . . a s y n c f o r p r o j e c t i n c o n n . e x e c u t e ( q u e r y ) : p r o j e c t s . a p p e n d ( p r o j e c t ) r e t u r n j s o n _ r e s p o n s e ( p r o j e c t s )