Python: rest_api
This commit is contained in:
parent
5f65385207
commit
6d20598706
1 changed files with 58 additions and 46 deletions
|
|
@ -1,11 +1,56 @@
|
||||||
import json
|
import json
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from copy import copy
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
VALID_HTTP_METHODS = ['GET', 'POST']
|
VALID_HTTP_METHODS = ['GET', 'POST']
|
||||||
|
|
||||||
|
|
||||||
|
class ApiMethodRegistry:
|
||||||
|
def __init__(self):
|
||||||
|
self.methods = {k: {} for k in VALID_HTTP_METHODS}
|
||||||
|
|
||||||
|
def register_url(self, url, http_method):
|
||||||
|
|
||||||
|
def actual_decorator(f):
|
||||||
|
|
||||||
|
@wraps(f)
|
||||||
|
def _wrapper(f_self, payload):
|
||||||
|
|
||||||
|
if payload:
|
||||||
|
payload = json.loads(payload)
|
||||||
|
# It would be essential to validate JSON schema here
|
||||||
|
|
||||||
|
f_result = f(f_self, payload)
|
||||||
|
|
||||||
|
return json.dumps(f_result,
|
||||||
|
default=lambda obj: obj.__dict__,
|
||||||
|
sort_keys=True)
|
||||||
|
|
||||||
|
self.methods[http_method][url] = _wrapper
|
||||||
|
|
||||||
|
return actual_decorator
|
||||||
|
|
||||||
|
|
||||||
|
class RestApiBase:
|
||||||
|
|
||||||
|
registry = ApiMethodRegistry()
|
||||||
|
|
||||||
|
def _process_request(self, method, url, payload):
|
||||||
|
methods = self.registry.methods[method]
|
||||||
|
|
||||||
|
# It would be natural to handle exceptions here
|
||||||
|
if url in methods.keys():
|
||||||
|
return methods[url](self, payload)
|
||||||
|
|
||||||
|
def get(self, url, payload=None):
|
||||||
|
return self._process_request('GET', url, payload)
|
||||||
|
|
||||||
|
def post(self, url, payload=None):
|
||||||
|
return self._process_request('POST', url, payload)
|
||||||
|
|
||||||
|
|
||||||
class User:
|
class User:
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
@ -40,59 +85,26 @@ class User:
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
class MethodRegistry:
|
class RestAPI(RestApiBase):
|
||||||
def __init__(self):
|
|
||||||
self.methods = {k: {} for k in VALID_HTTP_METHODS }
|
|
||||||
|
|
||||||
def register_url(self, url, http_method):
|
registry = copy(RestApiBase.registry)
|
||||||
|
|
||||||
def actual_decorator(f):
|
|
||||||
|
|
||||||
@wraps(f)
|
|
||||||
def _wrapper(f_self, payload):
|
|
||||||
|
|
||||||
if payload:
|
|
||||||
payload = json.loads(payload)
|
|
||||||
#It would be essential to validate JSON schema here
|
|
||||||
|
|
||||||
f_result = f(f_self, payload)
|
|
||||||
|
|
||||||
return json.dumps(f_result, default=lambda obj: obj.__dict__, sort_keys=True)
|
|
||||||
|
|
||||||
self.methods[http_method][url] = _wrapper
|
|
||||||
|
|
||||||
return actual_decorator
|
|
||||||
|
|
||||||
|
|
||||||
class RestAPI:
|
|
||||||
|
|
||||||
registry = MethodRegistry()
|
|
||||||
|
|
||||||
def __init__(self, database=None):
|
def __init__(self, database=None):
|
||||||
self._users = {user['name'] : User.from_dict(user) for user in database['users']} if database else {}
|
self._users = {user['name']: User.from_dict(user)
|
||||||
|
for user in database['users']} if database else {}
|
||||||
def _process_request(self, method, url, payload):
|
|
||||||
methods = self.registry.methods[method]
|
|
||||||
|
|
||||||
#It would be natural to handle exceptions here
|
|
||||||
if url in methods.keys():
|
|
||||||
return methods[url](self, payload)
|
|
||||||
|
|
||||||
def get(self, url, payload=None):
|
|
||||||
return self._process_request('GET', url, payload)
|
|
||||||
|
|
||||||
def post(self, url, payload=None):
|
|
||||||
return self._process_request('POST', url, payload)
|
|
||||||
|
|
||||||
@registry.register_url('/users', 'GET')
|
@registry.register_url('/users', 'GET')
|
||||||
def users(self, payload=None):
|
def users(self, payload=None):
|
||||||
if payload:
|
if payload:
|
||||||
requested_users = payload['users']
|
requested_user_names = payload['users']
|
||||||
response = [user for user in self._users.values() if user.name in requested_users]
|
users = [user for user in self._users.values()
|
||||||
|
if user.name in requested_user_names]
|
||||||
else:
|
else:
|
||||||
response = [user for user in self._users.values()]
|
users = [user for user in self._users.values()]
|
||||||
|
|
||||||
return {'users': response}
|
users = sorted(users, key=attrgetter('name'))
|
||||||
|
|
||||||
|
return {'users': users}
|
||||||
|
|
||||||
@registry.register_url('/add', 'POST')
|
@registry.register_url('/add', 'POST')
|
||||||
def add(self, payload=None):
|
def add(self, payload=None):
|
||||||
|
|
@ -112,5 +124,5 @@ class RestAPI:
|
||||||
self._users[lender].lend(borrower, amount)
|
self._users[lender].lend(borrower, amount)
|
||||||
self._users[borrower].borrow(lender, amount)
|
self._users[borrower].borrow(lender, amount)
|
||||||
|
|
||||||
return {'users': sorted([self._users[lender], self._users[borrower]], key=attrgetter('name'))}
|
return {'users': sorted([self._users[lender], self._users[borrower]],
|
||||||
|
key=attrgetter('name'))}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue