Improving the CRUD API endpoints

This commit is contained in:
Scott Idem
2023-07-10 16:35:04 -04:00
parent 60853bc281
commit 4f7ce57111
2 changed files with 233 additions and 47 deletions

View File

@@ -161,7 +161,7 @@ router = APIRouter()
# Working on the basic API CRUD - STI 2021-03-08
# Updated 2023-07-06
@router.get('/{obj_type_l1}/list')
@router.get('/{obj_type_l1}/{obj_type_l2}/list')
@router.get('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/list')
@@ -479,19 +479,28 @@ async def patch_obj(
# ### END ### API CRUD ### patch_obj() ###
@router.delete('/{obj_type_l1}/{obj_id}')
@router.delete('/{obj_type_l1}/{obj_type_l2}/{obj_id}')
@router.delete('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/{obj_id}')
async def delete_obj(
obj_type_l1: str=None,
# ### BEGIN ### API CRUD ### post_obj() ###
# Updated 2022-11-29
@router.post('/{obj_type_l1}/{obj_id}')
@router.post('/{obj_type_l1}/{obj_type_l2}/{obj_id}')
@router.post('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/{obj_id}')
async def post_obj(
crud: Api_Crud_Base,
obj_type_l1: Optional[str] = Query(..., max_length=50),
obj_type_l2: str = None,
obj_type_l3: str = None,
obj_id: str=None,
x_account_id: str = Header(...),
response: Response = Response,
obj_id: str = Query(..., min_length=11, max_length=22),
run_safety_check: bool = True,
# for_obj_type: Optional[str] = Query(None, max_length=50),
# for_obj_id: Optional[str] = Query(None, max_length=22),
commons: Common_Route_Params = Depends(common_route_params),
):
"""
Simple delete object type with an ID:
Simple post object type:
- **obj_type_l1, obj_type_l2, obj_type_l3**:
- Examples:
- /account = account
@@ -504,6 +513,144 @@ async def delete_obj(
- /order/cart/line = order_cart_line
- /lu/some_lookup = lu_some_lookup
"""
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
if crud.super_key == 'zp5PtX4zUsI': pass
elif crud.jwt:
# pass
log.warning('JWT was passed')
return mk_resp(data=False, status_code=501, response=commons.response, status_message='Token access for the API CRUD has not been implemented yet.')
else:
log.warning('Access key is missing or incorrect')
return mk_resp(data=False, status_code=400, response=commons.response)
# NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING
# time.sleep(1.5) # NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING
# NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING
debug_data = {}
debug_data['crud'] = crud
debug_data['create_key'] = crud.create_key
debug_data['read_key'] = crud.read_key
debug_data['update_key'] = crud.update_key
debug_data['delete_key'] = crud.delete_key
debug_data['data_list'] = crud.data_list
debug_data['obj_type_l1'] = obj_type_l1
debug_data['obj_type_l2'] = obj_type_l2
debug_data['obj_type_l3'] = obj_type_l3
debug_data['obj_id'] = obj_id
log.debug(debug_data)
if obj_type_l1 and obj_type_l2 and obj_type_l3:
obj_name = f'{obj_type_l1}_{obj_type_l2}_{obj_type_l3}'
if obj_name in obj_type_li:
#table_name = obj_type_li[obj_name]
#table_name = obj_type_li[obj_name]['tbl_name_update']
pass
else:
return mk_resp(data=False, status_code=400, response=commons.response)
elif obj_type_l1 and obj_type_l2:
obj_name = f'{obj_type_l1}_{obj_type_l2}'
if obj_name in obj_type_li:
#table_name = obj_type_li[obj_name]['tbl_name_update']
pass
else:
return mk_resp(data=False, status_code=400, response=commons.response)
elif obj_type_l1:
obj_name = f'{obj_type_l1}'
if obj_name in obj_type_li:
#table_name = obj_type_li[obj_name]['tbl_name_update']
pass
else:
return mk_resp(data=False, status_code=400, response=commons.response)
else:
log.warning('We should not be here')
return mk_resp(data=False, status_code=400, response=commons.response)
table_name = obj_type_li[obj_name].get('tbl_name_update')
exclude = obj_type_li[obj_name].get('exclude_for_db')
# ### SECTION ### Secondary data validation
# if obj_id := redis_lookup_id_random(record_id_random=obj_id, table_name=table_name): pass
# else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The object ID was invalid or not found.')
# NOTE: Doing a quick sanity check based on the object models and then dump to a dict to get rid of invalid fields. The other option is to just use the crud.data_list raw.
crud_data = crud.data_list
log.debug(crud_data.keys())
field_list = crud_data.keys()
if run_safety_check:
log.info('Running safety check by default')
base_name = obj_type_li[obj_name]['base_name']
obj_model = base_name(**crud.data_list) # .dict(by_alias=commons.by_alias, exclude_unset=commons.exclude_unset)
log.debug(obj_model)
# obj_dict = obj_model.dict(by_alias=commons.by_alias, exclude_unset=commons.exclude_unset, exclude=exclude)
obj_dict = obj_model.dict(by_alias=commons.by_alias, exclude_unset=commons.exclude_unset, include=field_list)
log.debug(obj_dict)
crud_data = obj_dict
else:
log.warning('The default safety check was not run!')
obj_dict = crud_data
# NOTE: Add a check for the object ID... assuming it is a random ID string for now. Using rm_id_random. That helps with some field names.
if sql_result := sql_insert(data=crud_data, table_name=table_name, rm_id_random=True, log_lvl=logging.INFO):
log.info('The record was inserted.')
log.debug(sql_result)
resp_data = {}
resp_data['table_name'] = table_name
resp_data['request_data'] = obj_dict
resp_data['obj_id'] = sql_result # The ID should be returned
return mk_resp(data=resp_data, response=commons.response) #, details=debug_data)
elif sql_result == None:
log.info('The record was probably not found to be updated.')
log.debug(sql_result)
return mk_resp(data=None, status_code=404, status_message='The record was probably not found to be updated.', response=commons.response)
else:
log.info('Something unexpected happened while trying to runt he SQL UPDATE. The fields or field values passed may not be valid for the table.')
log.debug(sql_result)
return mk_resp(data=False, status_code=400, status_message='Something unexpected happened while trying to runt he SQL UPDATE. The fields or field values passed may not be valid for the table.', response=commons.response)
# ### END ### API CRUD ### post_obj() ###
# ### BEGIN ### API CRUD ### delete_obj() ###
# Updated 2023-07-10
@router.delete('/{obj_type_l1}/{obj_id}')
@router.delete('/{obj_type_l1}/{obj_type_l2}/{obj_id}')
@router.delete('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/{obj_id}')
async def delete_obj(
obj_type_l1: str=None,
obj_type_l2: str=None,
obj_type_l3: str=None,
obj_id: str=None,
method: str = 'delete', # None, delete, disable, hide
# x_account_id: str = Header(...),
# response: Response = Response,
commons: Common_Route_Params = Depends(common_route_params),
):
"""
Simple delete object type with an ID:
- **obj_type_l1, obj_type_l2, obj_type_l3**:
- Examples:
- /account = account
- /user = user
- /user/role = user_role
- /event = event
- /event/exhibit = event_exhibit
- /event/person/profile = event_person_profile
- /order = order
- /order/line = order_line
- /lu/some_lookup = lu_some_lookup
"""
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
@@ -515,37 +662,76 @@ async def delete_obj(
log.debug(debug_data)
# NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING
# time.sleep(1.5) # NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING
# NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING NOTE: WARNING
if obj_type_l1 and obj_type_l2 and obj_type_l3:
obj_name = f'{obj_type_l1}_{obj_type_l2}_{obj_type_l3}'
if obj_name in obj_type_li:
pass
else:
return mk_resp(data=False, status_code=400, response=response)
return mk_resp(data=False, status_code=400, response=commons.response)
elif obj_type_l1 and obj_type_l2:
obj_name = f'{obj_type_l1}_{obj_type_l2}'
if obj_name in obj_type_li:
pass
else:
return mk_resp(data=False, status_code=400, response=response)
return mk_resp(data=False, status_code=400, response=commons.response)
elif obj_type_l1:
obj_name = f'{obj_type_l1}'
if obj_name in obj_type_li:
pass
else:
return mk_resp(data=False, status_code=400, response=response)
return mk_resp(data=False, status_code=400, response=commons.response)
else:
log.warning('We should not be here')
return mk_resp(data=False, status_code=400, response=response)
return mk_resp(data=False, status_code=400, response=commons.response)
table_name = obj_name # obj_type_li[obj_name]['table_name'] # NOTE: Don't try to use the view!
# NOTE: Add a check for the object ID... assuming it is a random ID string for now.
if method == 'delete' or method is None:
sql_result = sql_delete(table_name=table_name, record_id_random=obj_id)
log.debug(sql_result)
elif method == 'disable':
data = {'enable': False}
sql_result = sql_update(data=data, table_name=table_name, record_id_random=obj_id, rm_id_random=True, log_lvl=logging.INFO)
elif method == 'hide':
data = {'hide': True}
sql_result = sql_update(data=data, table_name=table_name, record_id_random=obj_id, rm_id_random=True, log_lvl=logging.INFO)
else:
log.warning('We should not be here')
return mk_resp(data=False, status_code=400, response=commons.response)
if sql_result:
resp_data = True
log.info('The record was found and deleted or updated.')
elif sql_result == None:
resp_data = None
log.info('The record was probably not found to be deleted and or updated.')
else:
resp_data = False
log.info('Something unexpected happened while trying to run the SQL DELETE and or UPDATE. The fields or field values passed may not be valid for the table.')
return mk_resp(data=resp_data, response=response) #, details=debug_data)
resp_details = ''
if method == 'delete' and sql_result:
resp_details = f'Object type: {obj_name} Object ID: {obj_id}; deleted'
return mk_resp(data=resp_data, details=resp_details, response=commons.response) #, details=debug_data)
elif method == 'hide' and sql_result:
resp_details = f'Object type: {obj_name} Object ID: {obj_id}; hidden'
return mk_resp(data=resp_data, details=resp_details, response=commons.response) #, details=debug_data)
elif method == 'disable' and sql_result:
resp_details = f'Object type: {obj_name} Object ID: {obj_id}; disabled'
return mk_resp(data=resp_data, details=resp_details, response=commons.response) #, details=debug_data)
elif sql_result is None:
resp_details = f'Not found: Object type: {obj_name} Object ID: {obj_id}; {method}'
return mk_resp(data=resp_data, status_code=404, details=resp_details, response=commons.response) #, details=debug_data)
else:
resp_details = f'Unexpected result: Object type: {obj_name} Object ID: {obj_id}; {method}'
return mk_resp(data=resp_data, status_code=400, details=resp_details, response=commons.response) #, details=debug_data)
# ### END ### API CRUD ### delete_obj() ###
def post_obj_template(

View File

@@ -260,33 +260,33 @@ async def get_event_id_event_abstract_obj_li(
# ### END ### API Event Abstract ### get_event_id_event_abstract_obj_li() ###
# ### BEGIN ### API Event Abstract ### delete_event_abstract_obj() ###
# Updated 2023-03-22
@router.delete('/event/abstract/{event_abstract_id}', response_model=Resp_Body_Base)
def delete_event_abstract_obj(
event_abstract_id: str = Query(..., min_length=11, max_length=22),
# # ### BEGIN ### API Event Abstract ### delete_event_abstract_obj() ###
# # Updated 2023-03-22
# @router.delete('/event/abstract/{event_abstract_id}', response_model=Resp_Body_Base)
# def delete_event_abstract_obj(
# event_abstract_id: str = Query(..., min_length=11, max_length=22),
method: str = None, # None, delete, disable, hide
# method: str = None, # None, delete, disable, hide
commons: Common_Route_Params = Depends(common_route_params),
):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
# commons: Common_Route_Params = Depends(common_route_params),
# ):
# log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
# log.debug(locals())
# ### SECTION ### Secondary data validation
if event_abstract_id := redis_lookup_id_random(record_id_random=event_abstract_id, table_name='event_abstract'): pass
else: return mk_resp(data=None, status_code=404, response=response, status_message='The Event Abstract ID was invalid or not found.')
# # ### SECTION ### Secondary data validation
# if event_abstract_id := redis_lookup_id_random(record_id_random=event_abstract_id, table_name='event_abstract'): pass
# else: return mk_resp(data=None, status_code=404, response=response, status_message='The Event Abstract ID was invalid or not found.')
if event_abstract_obj_result := remove_event_abstract_obj(
event_abstract_id = event_abstract_id,
method = method,
):
log.info('Delete successful. Returning True')
return mk_resp(data=True, response=response) # Success
elif event_abstract_obj_result is None: # None
log.info('No results')
return mk_resp(data=None, status_code=404, response=response) # Not Found
else:
log.warning('Likely bad request')
return mk_resp(data=False, status_code=400, response=response) # Bad Request
# ### END ### API Event Abstract ### delete_event_abstract_obj() ###
# if event_abstract_obj_result := remove_event_abstract_obj(
# event_abstract_id = event_abstract_id,
# method = method,
# ):
# log.info('Delete successful. Returning True')
# return mk_resp(data=True, response=commons.response) # Success
# elif event_abstract_obj_result is None: # None
# log.info('No results')
# return mk_resp(data=None, status_code=404, response=commons.response) # Not Found
# else:
# log.warning('Likely bad request')
# return mk_resp(data=False, status_code=400, response=commons.response) # Bad Request
# # ### END ### API Event Abstract ### delete_event_abstract_obj() ###