import json from django.http import * from .api_params import * api_methods_dict = {} def api_make_response(response): return API_OK_OBJ | {"response": response} # def api_make_param(name, arg_class, description, required=True): # return { # "name": name, # "type": arg_class, # "description": description, # "required": required # } # API_PARAM_ACCESS_TOKEN = api_make_param( # "access_token", # AccessToken, # "Токен, выданный методом account.auth" # ) def default_serializer(obj): try: return obj.to_json() except Exception: return str(obj) def api_method(func_name, doc="", params: list or None = None, returns=""): """ Декоратор для методов API, автоматически валидирует и передает параметры методам """ def actual_decorator(func): async def wrapper(__raw_request, **kwargs): print(f"> call method {func_name} with params {kwargs}. method params: {params}") errors = [] func_args = {} for p in params: try: if not isinstance(p, ApiParam): raise Exception(API_ERROR_INTERNAL_ERROR, f"param {p} is not instance of ApiParam class") name = p.get_name() if isinstance(p, ApiRequestParam): func_args[name] = __raw_request else: value = kwargs[name] if name in kwargs else None if asyncio.iscoroutinefunction(p.validate): func_args[name] = await p.validate(value) else: func_args[name] = p.validate(value) except Exception as ex: errors.append(ex) # print(f"errors: {errors}, args: {func_args}") if len(errors) > 0: if len(errors) == 1: obj = make_error_object(errors[0]) else: obj = make_error_object(errors) response = HttpResponseBadRequest(json.dumps(obj, default=default_serializer, ensure_ascii=False, indent=4)) response.headers["Content-type"] = "application/json; charset=utf-8" return response else: try: if asyncio.iscoroutinefunction(func): out = await func(**func_args) else: out = func(**func_args) except Exception as ex: return make_error_object(ex) if out is None: obj = make_error_object(Exception(API_ERROR_INTERNAL_ERROR, "method returned null object")) response = HttpResponseServerError(json.dumps(obj, default=default_serializer, ensure_ascii=False, indent=4)) response.headers["Content-type"] = "application/json; charset=utf-8" return response if not isinstance(out, dict) and not isinstance(out, HttpResponse): obj = make_error_object(Exception(API_ERROR_INTERNAL_ERROR, "method returned invalid object type")) response = HttpResponseServerError(json.dumps(obj, default=default_serializer, ensure_ascii=False, indent=4)) response.headers["Content-type"] = "application/json; charset=utf-8" return response return out api_methods_dict[func_name] = { "doc": doc, "params": params, "func": wrapper, "returns": returns } return wrapper return actual_decorator