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')
@@ -473,25 +473,34 @@ async def patch_obj(
log.debug(sql_result) 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) return mk_resp(data=None, status_code=404, status_message='The record was probably not found to be updated.', response=commons.response)
else: 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.info('Something unexpected happened while trying to run the SQL UPDATE. The fields or field values passed may not be valid for the table.')
log.debug(sql_result) 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) 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 ### 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}')
obj_type_l2: str=None, @router.post('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/{obj_id}')
obj_type_l3: str=None, async def post_obj(
obj_id: str=None, crud: Api_Crud_Base,
x_account_id: str = Header(...), obj_type_l1: Optional[str] = Query(..., max_length=50),
response: Response = Response, obj_type_l2: str = None,
obj_type_l3: str = None,
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**: - **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.
sql_result = sql_delete(table_name=table_name, record_id_random=obj_id)
log.debug(sql_result)
resp_data = True 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)
return mk_resp(data=resp_data, response=response) #, details=debug_data) 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.')
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() ###