Slide 1

Slide 1 text

Asyncio Stack & React.js or Development on the Edge Igor Davydenko EuroPython 2015

Slide 2

Slide 2 text

Intro

Slide 3

Slide 3 text

I am... Igor Davydenko Python & React.js developer From Kyiv, Ukraine Works on Ezhome Inc. Primarly designs & develops backend API Personal Site @ GitHub @ Twitter

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

In Total Python developer for past 8 years Using Django from 0.96 Using Flask from 0.7 Still not satisfied …

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Hello, JavaScript!

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

JavaScript was bad Prototype was big and hard jQuery was small and easy. Somewhen, decades ago jQuery UI :( jQuery plugins :( :(

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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 >

Slide 15

Slide 15 text

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 >

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Welcome ECMAScript 2015 Previously known as ES6

Slide 18

Slide 18 text

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 " ;

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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 ( ) ; } )

Slide 21

Slide 21 text

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 ( ) ;

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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 } = { . . . } ;

Slide 24

Slide 24 text

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 ;

Slide 25

Slide 25 text

And More Learn ES2015 Default + Rest + Spread Iterators + For..Of Generators Improved Unicode Module Loaders Proxies Symbols ...

Slide 26

Slide 26 text

And More ES2016, ES2017, ... Comprehensions Class Properties Function Bind Async Functions Decorators ...

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

How to Use? Use Babel for all good things! Supports browserify, webpack, ... Emerges eslint as your one and only JS linter

Slide 29

Slide 29 text

So here comes React.js

Slide 30

Slide 30 text

React.js Painless UI Framework Virtual DOM One-way reactive data flow Has a strong community around

Slide 31

Slide 31 text

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 " ) ) ;

Slide 32

Slide 32 text

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 " ) ) ;

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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 } / > )

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

JavaScript is good now, but what about Python?

Slide 41

Slide 41 text

Let me introduce Asyncio Stack

Slide 42

Slide 42 text

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)

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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/

Slide 47

Slide 47 text

And many others Python Asyncio Resources MySQL: aiomysql Mongo: asyncio_mongo CouchDB: aiocouchdb ElasticSearch: aioes Memcached: aiomcache AMQP: aioamqp ØMQ: aiozmq

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

Even web-frameworks available muffin Induction Spanner.py Growler

Slide 50

Slide 50 text

aiohttp.web

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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 )

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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 )

Slide 59

Slide 59 text

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 )

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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 )

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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 }

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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.

Slide 71

Slide 71 text

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 ( ) , } )

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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 }

Slide 74

Slide 74 text

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 >

Slide 75

Slide 75 text

And More WebSockets Expect Header Custom Conditions for Routes Lookup Class Based Handlers And I say it again, WebSockets

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

Real World Usage

Slide 78

Slide 78 text

Structure yourproject api storage.py views.py auth api.py views.py static templates app.py settings.py storage.py views.py

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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 ( ) , } } )

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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 )

Slide 85

Slide 85 text

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 )

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

Why you might need Asyncio Stack?

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

Cause it cool and trendy!

Slide 91

Slide 91 text

Database-less API

Slide 92

Slide 92 text

Requests to the external API

Slide 93

Slide 93 text

Async code execution

Slide 94

Slide 94 text

Predictable async IO

Slide 95

Slide 95 text

Summary

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

Questions?

Slide 100

Slide 100 text

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 )