145 lines
8.1 KiB
Python
145 lines
8.1 KiB
Python
import datetime, hashlib, logging, os, pytz, redis, secrets
|
|
|
|
from typing import Dict, List, Optional, Set, Union
|
|
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator
|
|
|
|
from app.db_sql import redis_lookup_id_random
|
|
from app.lib_general import log, logging, Response, status
|
|
|
|
from app.config import settings
|
|
|
|
from app.models.common_field_schema import base_fields, default_num_bytes
|
|
|
|
|
|
# ### BEGIN ### API Response Model ### Resp_Body_Base() ###
|
|
# The pydantic BaseModel to help make consistent REST responses.
|
|
# Updated 2021-03-05
|
|
class Resp_Body_Base(BaseModel):
|
|
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
|
log.debug(locals())
|
|
|
|
# test_prop: Optional[str] = Field(
|
|
# alias = 'test_prop_alias'
|
|
# )
|
|
|
|
data: Union[list, dict]
|
|
meta: Optional[dict]
|
|
# ### END ### API Response Model ### Resp_Body_Base() ###
|
|
|
|
|
|
# ### BEGIN ### API Response Model ### mk_resp() ###
|
|
# The method for making responses for REST. Returns a dict, but currently uses Resp_Body_Base inside the function.
|
|
# Update 2021-08-23
|
|
def mk_resp(
|
|
data: None|bool|dict|list,
|
|
tmp_file_path: None|str = None,
|
|
dict_to_json: bool = False,
|
|
status_code: int = 200,
|
|
status_message: str = '',
|
|
status_name: str = '',
|
|
success: bool = True,
|
|
details: str = '',
|
|
include: dict = None,
|
|
exclude: dict = None,
|
|
by_alias: bool = True,
|
|
exclude_unset: bool = False,
|
|
response: Response = None
|
|
) -> dict:
|
|
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
|
log.debug(locals())
|
|
|
|
if data is None: data_out = { 'result': data }
|
|
elif data == False: data_out = { 'result': data }
|
|
elif data == True: data_out = { 'result': data }
|
|
elif isinstance(data, dict):
|
|
log.info('Data type is a dict')
|
|
data_out = data
|
|
elif isinstance(data, list):
|
|
log.info('Data type is a list')
|
|
data_out = data
|
|
elif isinstance(data, int):
|
|
log.info('Data type is an int')
|
|
data_out = { 'result': data }
|
|
elif isinstance(data, str):
|
|
log.info('Data type is a str')
|
|
data_out = { 'result': data }
|
|
else: # Assuming it is still and object. This should be improved. Example model type: "<class 'app.models.account_models.Account_Base'>"
|
|
log.info('Data type is other')
|
|
data_out = data.dict(include=include, exclude=exclude, by_alias=by_alias, exclude_unset=exclude_unset)
|
|
# log.debug(data_out)
|
|
|
|
resp_body = {}
|
|
resp_body['data'] = data_out
|
|
resp_body['meta'] = {}
|
|
resp_body['meta']['details'] = details
|
|
resp_body['meta']['status_code'] = status_code
|
|
if status_message:
|
|
resp_body['meta']['status_message'] = status_message
|
|
else:
|
|
resp_body['meta']['status_message'] = http_status_li[status_code]['message']
|
|
resp_body['meta']['status_name'] = http_status_li[status_code]['name']
|
|
resp_body['meta']['success'] = success
|
|
resp_body['meta']['tmp_file_path'] = tmp_file_path
|
|
|
|
if isinstance(data, bool):
|
|
resp_body['meta']['data_type'] = 'bool'
|
|
elif isinstance(data, int):
|
|
resp_body['meta']['data_type'] = 'int'
|
|
elif isinstance(data, str):
|
|
resp_body['meta']['data_type'] = 'str'
|
|
elif isinstance(data, dict):
|
|
resp_body['meta']['data_type'] = 'dict'
|
|
elif isinstance(data, list):
|
|
resp_body['meta']['data_type'] = 'list'
|
|
resp_body['meta']['data_list_count'] = len(data)
|
|
|
|
if response:
|
|
log.debug(response)
|
|
if status_code == 400:
|
|
log.warning('Likely bad request')
|
|
response.status_code = status.HTTP_400_BAD_REQUEST
|
|
elif status_code == 401: response.status_code = status.HTTP_401_UNAUTHORIZED
|
|
# elif status_code == 402: response.status_code = status.HTTP_402_X
|
|
elif status_code == 403: response.status_code = status.HTTP_403_FORBIDDEN
|
|
elif status_code == 404:
|
|
log.info('No results')
|
|
response.status_code = status.HTTP_404_NOT_FOUND
|
|
elif status_code == 408: response.status_code = status.HTTP_408_REQUEST_TIMEOUT
|
|
elif status_code == 429: response.status_code = status.HTTP_429_TOO_MANY_REQUESTS
|
|
elif status_code == 500: response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
elif status_code == 501: response.status_code = status.HTTP_501_NOT_IMPLEMENTED
|
|
elif status_code == 502: response.status_code = status.HTTP_502_BAD_GATEWAY
|
|
elif status_code == 503: response.status_code = status.HTTP_503_SERVICE_UNAVAILABLE
|
|
elif status_code == 504: response.status_code = status.HTTP_504_GATEWAY_TIMEOUT
|
|
|
|
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
|
# log.debug(resp_body)
|
|
# log.debug(type(resp_body['data']))
|
|
|
|
# import json
|
|
# with open('data.txt', 'w') as outfile:
|
|
# json.dump(resp_body['data'], outfile)
|
|
|
|
resp_body_obj = Resp_Body_Base(**resp_body)
|
|
log.debug(resp_body_obj)
|
|
resp_body_dict = resp_body_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset)
|
|
log.debug(resp_body_dict)
|
|
|
|
return resp_body_dict
|
|
# ### END ### API Response Model ### mk_resp() ###
|
|
|
|
|
|
http_status_li = {}
|
|
http_status_li[200] = { 'name': 'OK', 'message': 'The request has succeeded.' }
|
|
http_status_li[400] = { 'name': 'Bad Request', 'message': 'The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.' }
|
|
http_status_li[401] = { 'name': 'Unauthorized', 'message': 'The server could not verify that you are authorized to access the URL requested. You either supplied the wrong credentials (e.g. a bad password), or your browser does not understand how to supply the credentials required.' }
|
|
http_status_li[402] = { 'name': '?Request Failed?', 'message': '??The parameters were valid but the request failed.??' }
|
|
http_status_li[403] = { 'name': 'Forbidden', 'message': 'The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.' }
|
|
http_status_li[404] = { 'name': 'Not Found', 'message': 'The requested resource does not exist.' }
|
|
http_status_li[409] = { 'name': 'Conflict', 'message': 'The request conflicts with another request (perhaps due to using the same idempotent key).' }
|
|
http_status_li[429] = { 'name': 'Too Many Requests', 'message': 'Too many requests hit the API too quickly. We recommend an exponential backoff of your requests.' }
|
|
http_status_li[500] = { 'name': 'Internal Server Error', 'message': 'The server encountered an unexpected condition which prevented it from fulfilling the request.' }
|
|
http_status_li[501] = { 'name': 'Not Implemented', 'message': 'The server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.' }
|
|
http_status_li[502] = { 'name': 'Bad Gateway', 'message': 'The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request.' }
|
|
http_status_li[503] = { 'name': 'Service Unavailable', 'message': 'The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. The implication is that this is a temporary condition which will be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header. If no Retry-After is given, the client SHOULD handle the response as it would for a 500 response.' }
|
|
http_status_li[504] = { 'name': 'Gateway Timeout', 'message': 'The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server (e.g. DNS) it needed to access in attempting to complete the request.' } |