python
August 24, 2021
Обновленческое
Версия 0.1.5. Добавил класс PydanticHandler для поддержки POST-запросов в формате датаклассов pydantic.
Подобности тут: https://github.com/vlakir/cleanapi
Добавил в свой текущий проект. Объем кода api-сервера сократился раза в 3.
Было:
from cleanapi.server import BaseHandler
from app_logger import get_logger
from utils import process_error
import json
import pydantic
from asgiref.sync import sync_to_async
from tornado.web import RequestHandler
from abc import ABC
from common_dicts import *
from common_dataclasses import FramesRequest, FramesResult
from module_db.db_core import WorkDatabase
from utils import get_config_setting
from common_dicts import is_token_valid
url_tail = '/api/v1/frames.json'
logger = get_logger(__name__)
print_benchmark = get_config_setting('COMMON', 'print_benchmark').lower() == 'true'
class Handler(BaseHandler, RequestHandler, ABC):
"""
Хендлер API-запроса на список систем координат
"""
async def post(self):
logger.info(f'Поступил входящий запрос на список систем координат')
errors = []
try:
body_json_dict = json.loads(self.request.body)
except (json.decoder.JSONDecodeError, TypeError, ValueError) as ex:
process_error('000003', errors, str(ex), logger)
status_code = 400
self.set_status(status_code)
self.write({'errors': errors})
return
try:
input_request = FramesRequest(**body_json_dict)
if not is_token_valid(input_request.token):
raise ValueError("Некорректный токен доступа")
except pydantic.error_wrappers.ValidationError as ex:
process_error('000003', errors, json.loads(ex.json()), logger)
status_code = 400
self.set_status(status_code)
self.write({'errors': errors})
return
except ValueError as ex:
process_error('000007', errors, str(ex), logger)
status_code = 400
self.set_status(status_code)
self.write({'errors': errors})
return
try:
result = await sync_to_async(_process)(input_request)
except pydantic.error_wrappers.ValidationError as ex:
process_error('000009', errors, json.loads(ex.json()), logger)
status_code = 400
self.set_status(status_code)
self.write({'errors': errors})
return
except Exception as ex:
process_error('000009', errors, f'{str(ex.__class__.__name__)}: {str(ex)}', logger)
status_code = 400
self.set_status(status_code)
self.write({'errors': errors})
return
logger.info(f'Запрос на список систем координат выполнен.')
if len(result.errors) == 0:
result.errors = None
status_code = 200
else:
status_code = 400
output_json = result.json(exclude_none=True)
self.set_status(status_code)
self.write(output_json)
# noinspection PyUnusedLocal
def _process(request: FramesRequest) -> FramesResult:
"""
Обработчик запроса
:param request: входящий запрос
:type request: FramesRequest
:return: результат обработки
:rtype: FramesResult
"""
errors = []
work_database = WorkDatabase(errors, print_benchmark=print_benchmark)
frames = work_database.get_all_frames(errors, print_benchmark=print_benchmark,
benchmark_name='Получение справочника систем координат')
result = FramesResult(frames=frames, errors=errors)
return result
Стало:
from common_dataclasses import FramesRequest, FramesResult
from module_db.db_core import WorkDatabase
from module_frontend.app_handler import AppHandler
url_tail = '/api/v1/frames.json'
# noinspection PyAbstractClass
class Handler(AppHandler):
"""
Хендлер API-запроса на список систем координат
"""
request_dataclass = FramesRequest
result_dataclass = FramesResult
# noinspection PyUnusedLocal
def process(self, request: request_dataclass) -> result_dataclass:
"""
Обработчик запроса
:param request: входящий запрос
:type request: FramesRequest
:return: результат обработки
:rtype: FramesResult
"""
self.logger.info(f'Обработка запроса на {url_tail}')
errors = []
work_database = WorkDatabase(errors, print_benchmark=self.print_benchmark)
frames = work_database.get_all_frames(errors, print_benchmark=self.print_benchmark,
benchmark_name='Получение справочника систем координат')
result = FramesResult(frames=frames, errors=errors)
return resultИ так в каждом хэндлере, а их у меня там порядка двух десятков