Python: rest_api

This commit is contained in:
Dmitry Kokorin 2021-07-05 17:40:45 +03:00
parent 5f65385207
commit 6d20598706

View file

@ -1,11 +1,56 @@
import json
from collections import defaultdict
from copy import copy
from functools import wraps
from operator import attrgetter
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:
def __init__(self, name):
self.name = name
@ -40,59 +85,26 @@ class User:
return user
class MethodRegistry:
def __init__(self):
self.methods = {k: {} for k in VALID_HTTP_METHODS }
class RestAPI(RestApiBase):
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 RestAPI:
registry = MethodRegistry()
registry = copy(RestApiBase.registry)
def __init__(self, database=None):
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)
self._users = {user['name']: User.from_dict(user)
for user in database['users']} if database else {}
@registry.register_url('/users', 'GET')
def users(self, payload=None):
if payload:
requested_users = payload['users']
response = [user for user in self._users.values() if user.name in requested_users]
requested_user_names = payload['users']
users = [user for user in self._users.values()
if user.name in requested_user_names]
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')
def add(self, payload=None):
@ -112,5 +124,5 @@ class RestAPI:
self._users[lender].lend(borrower, 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'))}