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 # 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}/list')
@router.get('/{obj_type_l1}/{obj_type_l2}/list') @router.get('/{obj_type_l1}/{obj_type_l2}/list')
@router.get('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/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() ### # ### END ### API CRUD ### patch_obj() ###
@router.delete('/{obj_type_l1}/{obj_id}')
@router.delete('/{obj_type_l1}/{obj_type_l2}/{obj_id}') # ### BEGIN ### API CRUD ### post_obj() ###
@router.delete('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/{obj_id}') # Updated 2022-11-29
async def delete_obj( @router.post('/{obj_type_l1}/{obj_id}')
obj_type_l1: str=None, @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_l2: str = None,
obj_type_l3: str = None, obj_type_l3: str = None,
obj_id: str=None, obj_id: str = Query(..., min_length=11, max_length=22),
x_account_id: str = Header(...),
response: Response = Response, 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**: - **obj_type_l1, obj_type_l2, obj_type_l3**:
- Examples: - Examples:
- /account = account - /account = account
@@ -504,6 +513,144 @@ async def delete_obj(
- /order/cart/line = order_cart_line - /order/cart/line = order_cart_line
- /lu/some_lookup = lu_some_lookup - /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.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
@@ -515,37 +662,76 @@ async def delete_obj(
log.debug(debug_data) 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: if obj_type_l1 and obj_type_l2 and obj_type_l3:
obj_name = f'{obj_type_l1}_{obj_type_l2}_{obj_type_l3}' obj_name = f'{obj_type_l1}_{obj_type_l2}_{obj_type_l3}'
if obj_name in obj_type_li: if obj_name in obj_type_li:
pass pass
else: 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: elif obj_type_l1 and obj_type_l2:
obj_name = f'{obj_type_l1}_{obj_type_l2}' obj_name = f'{obj_type_l1}_{obj_type_l2}'
if obj_name in obj_type_li: if obj_name in obj_type_li:
pass pass
else: 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: elif obj_type_l1:
obj_name = f'{obj_type_l1}' obj_name = f'{obj_type_l1}'
if obj_name in obj_type_li: if obj_name in obj_type_li:
pass pass
else: else:
return mk_resp(data=False, status_code=400, response=response) return mk_resp(data=False, status_code=400, response=commons.response)
else: else:
log.warning('We should not be here') 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! 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. # 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) sql_result = sql_delete(table_name=table_name, record_id_random=obj_id)
log.debug(sql_result) 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 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( 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() ### # ### END ### API Event Abstract ### get_event_id_event_abstract_obj_li() ###
# ### BEGIN ### API Event Abstract ### delete_event_abstract_obj() ### # # ### BEGIN ### API Event Abstract ### delete_event_abstract_obj() ###
# Updated 2023-03-22 # # Updated 2023-03-22
@router.delete('/event/abstract/{event_abstract_id}', response_model=Resp_Body_Base) # @router.delete('/event/abstract/{event_abstract_id}', response_model=Resp_Body_Base)
def delete_event_abstract_obj( # def delete_event_abstract_obj(
event_abstract_id: str = Query(..., min_length=11, max_length=22), # 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), # commons: Common_Route_Params = Depends(common_route_params),
): # ):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL # log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) # log.debug(locals())
# ### SECTION ### Secondary data validation # # ### SECTION ### Secondary data validation
if event_abstract_id := redis_lookup_id_random(record_id_random=event_abstract_id, table_name='event_abstract'): pass # 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.') # 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( # if event_abstract_obj_result := remove_event_abstract_obj(
event_abstract_id = event_abstract_id, # event_abstract_id = event_abstract_id,
method = method, # method = method,
): # ):
log.info('Delete successful. Returning True') # log.info('Delete successful. Returning True')
return mk_resp(data=True, response=response) # Success # return mk_resp(data=True, response=commons.response) # Success
elif event_abstract_obj_result is None: # None # elif event_abstract_obj_result is None: # None
log.info('No results') # log.info('No results')
return mk_resp(data=None, status_code=404, response=response) # Not Found # return mk_resp(data=None, status_code=404, response=commons.response) # Not Found
else: # else:
log.warning('Likely bad request') # log.warning('Likely bad request')
return mk_resp(data=False, status_code=400, response=response) # Bad Request # return mk_resp(data=False, status_code=400, response=commons.response) # Bad Request
# ### END ### API Event Abstract ### delete_event_abstract_obj() ### # # ### END ### API Event Abstract ### delete_event_abstract_obj() ###