unified return structure to use error_field instead of message key to correspond to API specification

This commit is contained in:
Daniel Schick 2024-09-16 14:17:30 +02:00
parent a68a768277
commit 5ce866936d
13 changed files with 64 additions and 63 deletions

View File

@ -22,15 +22,15 @@ def get_request_code(code_id):
class RequestStatusCode(ABC):
def __init__(self):
return
@abstractmethod
def __call__(self, data):
raise NotImplementedError("any default status code object must be callable")
@abstractmethod
def status_code(self):
raise NotImplementedError("any default status code object should return an integer")
@abstractmethod
def response(self, data):
raise NotImplementedError("the response method should return a binary json object. typically, json.dumps is used")
@ -38,7 +38,7 @@ class RequestStatusCode(ABC):
def headers(self):
return {'Content-Type': 'application/json; charset=utf-8'}
class RequestCode_HTTP_200_OK(RequestStatusCode):
def __init__(self) -> None:
@ -46,13 +46,13 @@ class RequestCode_HTTP_200_OK(RequestStatusCode):
def __call__(self, data):
return (self.response(data), self.status_code(), self.headers())
def status_code(self):
return 200
def response(self, data):
return json.dumps(data, default=obj_dict)
class RequestCode_HTTP_201_CREATED(RequestStatusCode):
def __init__(self) -> None:
@ -60,10 +60,10 @@ class RequestCode_HTTP_201_CREATED(RequestStatusCode):
def __call__(self, data):
return (self.response(data), self.status_code(), self.headers())
def status_code(self):
return 201
def response(self, new_id):
return json.dumps({"id":new_id})
@ -74,10 +74,10 @@ class RequestCode_HTTP_400_BAD_REQUEST(RequestStatusCode):
def __call__(self, data):
return (self.response(data), self.status_code(), self.headers())
def status_code(self):
return 400
def response(self, data):
return json.dumps(data)
@ -88,15 +88,15 @@ class RequestCode_HTTP_403_FORBIDDEN(RequestStatusCode):
def __call__(self, data):
return (self.response(data), self.status_code(), self.headers())
def status_code(self):
return 403
def response(self, message="invalid credentials"):
result = {}
result["message"] = message
result["error_field"] = message
return json.dumps(result)
class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode):
def __init__(self) -> None:
@ -104,13 +104,13 @@ class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode):
def __call__(self, data):
return (self.response(data), self.status_code(), self.headers())
def status_code(self):
return 404
def response(self, message="no such record"):
result = {}
result["message"] = message
result["error_field"] = message
return json.dumps(result)
@ -120,12 +120,12 @@ class RequestCode_HTTP_500_INTERNAL_SERVER_ERROR(RequestStatusCode):
def __call__(self, data):
return (self.response(data), self.status_code(), self.headers())
def status_code(self):
return 500
def response(self, message="credential lookup mismatch"):
result = {}
result["message"] = message
result["error_field"] = message
return json.dumps(result)

View File

@ -13,7 +13,7 @@ def GetBerths(options):
try:
pooledConnection = local_db.getPoolConnection()
commands = pydapper.using(pooledConnection)
# only load berths to ports that the participant is assigned to
query = ("SELECT id, name, `lock`, owner_id, port_id, authority_id, created, modified, deleted FROM berth WHERE " +
"deleted = 0 AND + "
@ -26,7 +26,7 @@ def GetBerths(options):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500
finally:

View File

@ -35,7 +35,7 @@ def GetHistory(options):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps("call failed"), 500
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}

View File

@ -21,7 +21,7 @@ def GetUser(options):
"api_key, notify_email, notify_whatsapp, notify_signal, notify_popup, created, modified FROM user " +
"WHERE user_name = ?username? OR user_email = ?username?",
model=model.User, param={"username" : options["username"]})
if len(data) == 1:
if bcrypt.checkpw(options["password"].encode("utf-8"), bytes(data[0].password_hash, "utf-8")):
result = {
@ -39,18 +39,19 @@ def GetUser(options):
if len(data) > 1:
result = {}
result["message"] = "credential lookup mismatch"
result["error_field"] = "credential lookup mismatch"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
result = {}
result["message"] = "invalid credentials"
result["error_field"] = "invalid credentials"
return json.dumps(result), 403, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex:
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed: " + str(ex)
result["error_field"] = "call failed"
result["error_description"] = str(ex)
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:

View File

@ -27,7 +27,7 @@ def GetNotifications(options):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}

View File

@ -10,7 +10,7 @@ def GetParticipant(options):
"""
:param options: A dictionary containing all the paramters for the Operations
options["user_id"]: **Id of user**. *Example: 2*. User id returned by login call.
"""
"""
try:
pooledConnection = local_db.getPoolConnection()
@ -22,19 +22,19 @@ def GetParticipant(options):
"INNER JOIN user u WHERE u.participant_id = p.id and u.id = %d") % options["user_id"]
data = commands.query(query, model=model.Participant)
else:
# query = SQLQuery.get_participants()
# query = SQLQuery.get_participants()
# list only participants that are assigned to the same ports than participant of caller
query = ("SELECT p.id as id, name, street, postal_code, city, type, flags, p.created, p.modified, p.deleted " +
"FROM participant p " +
"FROM participant p " +
"JOIN participant_port_map ON p.id = participant_port_map.participant_id " +
"WHERE participant_port_map.port_id IN " +
"(SELECT port_id FROM participant_port_map where participant_id = %d) " +
"GROUP BY id " +
"ORDER BY p.name") % options["participant_id"]
data = commands.query(query, model=model.Participant)
for participant in data:
for participant in data:
port_query = "SELECT port_id FROM participant_port_map WHERE participant_id=?id?";
for record in commands.query(port_query, model=model.Port_Assignment, param={"id" : participant.id}, buffered=False):
pa = model.Port_Assignment(record.port_id)
@ -46,7 +46,7 @@ def GetParticipant(options):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps("call failed"), 500
finally:

View File

@ -21,7 +21,7 @@ def GetPorts(token):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500
finally:

View File

@ -42,7 +42,7 @@ def GetShipcalls(options):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
@ -52,8 +52,8 @@ def GetShipcalls(options):
def PostShipcalls(schemaModel):
"""
This function *executes* a post-request for shipcalls. The function is accessible as part of an API route.
This function *executes* a post-request for shipcalls. The function is accessible as part of an API route.
The common sequence is:
a) issue a request to the Flask API
b) BreCal.api.shipcalls.PostShipcalls, to verify the incoming request (which includes an authentification guard)
@ -62,8 +62,8 @@ def PostShipcalls(schemaModel):
:param schemaModel: The deserialized dict of the request
e.g.,
{
'ship_id': 1, 'type': 1, 'eta': datetime.datetime(2023, 7, 23, 7, 18, 19),
'voyage': '43B', 'tug_required': False, 'pilot_required': True, 'flags': 0,
'ship_id': 1, 'type': 1, 'eta': datetime.datetime(2023, 7, 23, 7, 18, 19),
'voyage': '43B', 'tug_required': False, 'pilot_required': True, 'flags': 0,
'pier_side': False, 'bunkering': True, 'recommended_tugs': 2, 'type_value': 1, 'evaluation_value': 0}
}
"""
@ -89,9 +89,9 @@ def PostShipcalls(schemaModel):
if key == "evaluation":
continue
if key == "evaluation_message":
continue
continue
if key == "type_value":
continue
continue
if key == "evaluation_value":
continue
if isNotFirst:
@ -151,7 +151,7 @@ def PostShipcalls(schemaModel):
commands.execute(query, {"scid" : new_id, "pid" : user_data["participant_id"], "uid" : user_data["id"]})
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
except ValidationError as ex:
return create_validation_error_response(ex, status_code=400, create_log=True)
@ -160,7 +160,7 @@ def PostShipcalls(schemaModel):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
@ -262,7 +262,7 @@ def PutShipcalls(schemaModel):
commands.execute(query, {"scid" : schemaModel["id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]})
return json.dumps({"id" : schemaModel["id"]}), 200
except ValidationError as ex:
return create_validation_error_response(ex, status_code=400, create_log=True)
@ -271,7 +271,7 @@ def PutShipcalls(schemaModel):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:

View File

@ -25,7 +25,7 @@ def GetShips(token):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
@ -91,7 +91,7 @@ def PostShip(schemaModel):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
@ -133,7 +133,7 @@ def PutShip(schemaModel):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
@ -157,12 +157,12 @@ def DeleteShip(options):
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
result = {}
result["message"] = "no such record"
result["error_field"] = "no such record"
return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex:
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}

View File

@ -35,7 +35,7 @@ def GetTimes(options):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
@ -104,7 +104,7 @@ def PostTimes(schemaModel):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
@ -164,7 +164,7 @@ def PutTimes(schemaModel):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:
@ -195,14 +195,14 @@ def DeleteTimes(options):
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
result = {}
result["message"] = "no such record"
result["error_field"] = "no such record"
return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex:
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:

View File

@ -63,7 +63,7 @@ def PutUser(schemaModel):
commands.execute(query, param={"password_hash" : password_hash, "id" : schemaModel["id"]})
else:
result = {}
result["message"] = "old password invalid"
result["error_field"] = "old password invalid"
return json.dumps(result), 400, {'Content-Type': 'application/json; charset=utf-8'}
return json.dumps({"id" : schemaModel["id"]}), 200
@ -72,7 +72,7 @@ def PutUser(schemaModel):
logging.error(ex)
print(ex)
result = {}
result["message"] = "call failed"
result["error_field"] = "call failed"
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
finally:

View File

@ -25,9 +25,9 @@ def auth_guard(role=None):
try:
user_data = check_jwt()
except Exception as e:
return json.dumps({"message" : f'{e}', "status": 401}), 401
return json.dumps({"error_field" : f'{e}', "status": 401}), 401
if role and role not in user_data['roles']:
return json.dumps({"message": 'Authorization required.', "status" : 403}), 403
return json.dumps({"error_field": 'Authorization required.', "status" : 403}), 403
# get on to original route
return route_function(*args, **kwargs)
decorated_function.__name__ = route_function.__name__

View File

@ -77,7 +77,7 @@ def create_werkzeug_error_response(ex:Forbidden, status_code:int=403, create_log
def create_dynamic_exception_response(ex, status_code:int=400, message:typing.Optional[str]=None, create_log:bool=True):
message = repr(ex) if message is None else message
json_response = create_default_json_response_format(error_field="Exception", error_description=message)
json_response["message"] = "call failed"
json_response["error_field"] = "call failed"
serialized_response = json.dumps(json_response, default=str)