From 6d20598706c250fd2bbe88b26ddd247e97754740 Mon Sep 17 00:00:00 2001 From: Dmitry Kokorin Date: Mon, 5 Jul 2021 17:40:45 +0300 Subject: [PATCH] Python: rest_api --- python/rest-api/rest_api.py | 104 ++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/python/rest-api/rest_api.py b/python/rest-api/rest_api.py index d798626..cc709df 100644 --- a/python/rest-api/rest_api.py +++ b/python/rest-api/rest_api.py @@ -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'))}