AOP in Python API design
-
Upload
meij200 -
Category
Technology
-
view
1.855 -
download
3
description
Transcript of AOP in Python API design
AOP in Python API design
Douwe van der Meij
Goldmund, Wyldebeast & Wunderliebe
Outline
● Problem description ● Aspect Oriented Programming ● Implementation
Case
● BioBench:○ Application for biogas installations
● Enter measurements ● Normalize data ● Calculate plant performance
Problem description
● Large code-base ● A lot of calculations ● Django web-interface ● Make calculations available via an API
Problem description
● Is there a library/framework? ● Are the alternatives? ● What is the actual impact of the feature? ● What aspects to take into account?
Problem description
● Aspects:○ Security○ Statistics / Logging○ Serialization○ More?
Problem description
def add(lhs, rhs): return lhs + rhs
Problem description
def add(lhs, rhs): return lhs + rhs def api_add(request): return add(request.args['lhs'], request.args['rhs'])
Problem description
def add(lhs, rhs): return lhs + rhs def api_add(request):
if request.args['token'] == valid: return add(request.args['lhs'], request.args['rhs']) raise Exception('Security error')
Problem description
def add(lhs, rhs): return lhs + rhs def api_add(request):
if request.args['token'] == valid: database.query().alter usage counter return add(request.args['lhs'], request.args['rhs']) raise Exception('Security error')
Problem description
def add(lhs, rhs): return lhs + rhs def api_add(request):
if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')
Problem description
def add(lhs, rhs): return lhs + rhs def api_add(request):
if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')
Problem description
def add(lhs, rhs): return lhs + rhs def api_add(request):
if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')
Problem description
Code base
Problem description
Code base
● Security
Problem description
Code base
● Statistics / Logging
Problem description
Code base
● Serialization
Problem description
Code base
● Dispatcher
Problem description
Code base
● Scattered / tangled code
Aspect Oriented Programming
● What is AOP? ● Separation of concerns (aspects) ● Avoid scattering / tangling
Code base
● Scattered / tangled code
Aspect Oriented Programming
Code base
● Avoid scattering
Aspect Oriented Programming
Code base
● Avoid tangling
Aspect Oriented Programming
Aspect Oriented Programming
● How to implement these marvelous concepts?○ In pure python please!
Aspect Oriented Programming
● Decorators!
Aspect Oriented Programming
● Aspect:○ Pointcuts○ Join points○ Advices
■ Before advices■ After advices■ Around advices
Aspect Oriented Programming
● Before advice○ Must execute the function (no side-effects)
def aspect(function): def advice(*args, **kwargs):
do something here return function(*args, **kwargs) return advice
Aspect Oriented Programming
● After advice○ Must execute the function (no side-effects)
def aspect(function): def advice(*args, **kwargs): result = function(*args, **kwargs)
do something here return result return advice
Aspect Oriented Programming
● Around advice○ Allowed to bypass the function
def aspect(function): def advice(*args, **kwargs):
do something here result = function(*args, **kwargs)
do something here return result return advice
Implementation
● How to apply it to our case?
Implementation
● The decorators
Implementation
● Security aspect○ Around advice
def secure(function): def advice(*args, **kwargs):
if valid token in request object: return function(*args, **kwargs) raise Exception('No valid token provided') return advice
Implementation
● Statistics aspect○ Before advice
def statistics(function): def advice(*args, **kwargs):
increase API usage count for the user logged in return function(*args, **kwargs) return advice
Implementation
● Serialization aspect○ Around advice
def serialize(function): def advice(format, *args, **kwargs): if not format in ['html', 'xml', 'json']:
raise exception result = function(*args, **kwargs)
make a http response of 'result' in the right format return advice
Implementation
● Dispatcher aspect○ Around advice
def dispatch(function): def advice(*args, **kwargs):
proxy the API call to a call to the core system return advice
Implementation
mapping = { 'api_function': (core_function, ['lhs', 'rhs']), 'create_token': (create_token, ['username', 'password']),}
Implementation
def dispatch(function): def advice(*args, **kwargs):
if API call in proxy mapping: core_function, params = mapping[API call] kwargs.update(extract(params, request)) return function(proxy=core_function,
params=params, *args, **kwargs)
raise exception return advice
Implementation
● The API itself
Implementation
@secure@serialize@statistics@dispatchdef api_call(*args, **kwargs): proxy_function = kwargs['proxy'] params = kwargs['params']
return proxy_function(extract params from kwargs)
Conclusion
● AOP offers some brilliant concepts in software engineering
● Separate your concerns / aspects
○ Avoid classical scattering and tangling