UNPKG

@energica-city/shared-amplify-utils

Version:

Shared utilities for AWS Amplify projects

267 lines 10.2 kB
import { RestErrors } from '../middleware/rest/RestErrors'; import { getErrorMessage, isNotFoundError, isValidationError, isConflictError, } from './helpers'; /** * Creates REST-aware query factory wrappers with automatic HTTP error mapping. * * Wraps standard QueryFactory operations to intercept database errors and convert * them to appropriate REST errors with proper HTTP status codes. This enables * consistent REST API error responses without manual error handling in each endpoint. * * **Error Mapping Strategy:** * - `"No data returned"` → 404 Not Found * - AppSync validation errors → 400 Bad Request * - Conflict/constraint violations → 409 Conflict * - All other errors → 500 Internal Server Error * * @template T - Model name type extending string * @template TTypes - Record of all available Amplify model types * @param rawModel - Original QueryFactory instance to wrap * @param modelName - Human-readable model name for error messages * @param context - Request context object for error logging and tracing * @returns REST-aware query operations that throw HTTP-appropriate errors * * @example * ```typescript * const restQueries = createRestAwareQueryOperations( * queries.User, * "User", * { requestId: "req-123", userId: "current-user" } * ); * * // Automatically throws 404 RestError if user not found * const user = await restQueries.get({ input: { userId: "123" } }); * ``` */ export function createRestAwareQueryOperations(rawModel, modelName, context) { return { get: createRestAwareGetOperation(rawModel, modelName, context), create: createRestAwareCreateOperation(rawModel, modelName, context), update: createRestAwareUpdateOperation(rawModel, modelName, context), delete: createRestAwareDeleteOperation(rawModel, modelName, context), list: createRestAwareListOperation(rawModel, modelName, context), queryIndex: createRestAwareQueryIndexOperation(rawModel, modelName, context), }; } /** * Internal factory functions that create REST-aware operation handlers. * These functions maintain type information and provide consistent error handling patterns. */ /** * Creates a REST-aware get operation with 404 error handling. * * @internal * @template TTypes - Record of all available Amplify model types * @template T - Model name as string literal * @param rawModel - Original QueryFactory instance * @param modelName - Human-readable model name for error messages * @param context - Request context for error logging * @returns Function that performs get operation with REST error handling */ function createRestAwareGetOperation(rawModel, modelName, context) { return async (props) => { try { return await rawModel.get(props); } catch (error) { const message = getErrorMessage(error); if (isNotFoundError(message)) { throw RestErrors.notFound(`${modelName} not found`, { ...context, modelName, searchCriteria: props.input, }, error); } else { throw RestErrors.internal(`Failed to retrieve ${modelName}`, { ...context, modelName, operation: 'get', searchCriteria: props.input, }, error); } } }; } /** * Creates a REST-aware create operation with validation and conflict error handling. * * @internal * @template TTypes - Record of all available Amplify model types * @template T - Model name as string literal * @param rawModel - Original QueryFactory instance * @param modelName - Human-readable model name for error messages * @param context - Request context for error logging * @returns Function that performs create operation with REST error handling */ function createRestAwareCreateOperation(rawModel, modelName, context) { return async (props) => { try { return await rawModel.create(props); } catch (error) { const message = getErrorMessage(error); if (isValidationError(message)) { throw RestErrors.validation(`Invalid data for ${modelName} creation`, { ...context, modelName, inputData: props.input, }, error); } else if (isConflictError(message)) { throw RestErrors.conflict(`${modelName} already exists or conflicts with existing data`, { ...context, modelName, inputData: props.input, }, error); } else { throw RestErrors.internal(`Failed to create ${modelName}`, { ...context, modelName, operation: 'create', inputData: props.input, }, error); } } }; } /** * Creates a REST-aware update operation with comprehensive error handling. * * @internal * @template TTypes - Record of all available Amplify model types * @template T - Model name as string literal * @param rawModel - Original QueryFactory instance * @param modelName - Human-readable model name for error messages * @param context - Request context for error logging * @returns Function that performs update operation with REST error handling */ function createRestAwareUpdateOperation(rawModel, modelName, context) { return async (props) => { try { return await rawModel.update(props); } catch (error) { const message = getErrorMessage(error); if (isNotFoundError(message)) { throw RestErrors.notFound(`${modelName} not found for update`, { ...context, modelName, updateCriteria: props.input, }, error); } else if (isValidationError(message)) { throw RestErrors.validation(`Invalid data for ${modelName} update`, { ...context, modelName, updateData: props.input, }, error); } else if (isConflictError(message)) { throw RestErrors.conflict(`Update conflicts with existing ${modelName} data`, { ...context, modelName, updateData: props.input, }, error); } else { throw RestErrors.internal(`Failed to update ${modelName}`, { ...context, modelName, operation: 'update', updateData: props.input, }, error); } } }; } /** * Creates a REST-aware delete operation with 404 error handling. * * @internal * @template TTypes - Record of all available Amplify model types * @template T - Model name as string literal * @param rawModel - Original QueryFactory instance * @param modelName - Human-readable model name for error messages * @param context - Request context for error logging * @returns Function that performs delete operation with REST error handling */ function createRestAwareDeleteOperation(rawModel, modelName, context) { return async (props) => { try { return await rawModel.delete(props); } catch (error) { const message = getErrorMessage(error); if (isNotFoundError(message)) { throw RestErrors.notFound(`${modelName} not found for deletion`, { ...context, modelName, deleteCriteria: props.input, }, error); } else { throw RestErrors.internal(`Failed to delete ${modelName}`, { ...context, modelName, operation: 'delete', deleteCriteria: props.input, }, error); } } }; } /** * Creates a REST-aware list operation with general error handling. * * @internal * @template TTypes - Record of all available Amplify model types * @template T - Model name as string literal * @param rawModel - Original QueryFactory instance * @param modelName - Human-readable model name for error messages * @param context - Request context for error logging * @returns Function that performs list operation with REST error handling */ function createRestAwareListOperation(rawModel, modelName, context) { return async (props) => { try { return await rawModel.list(props); } catch (error) { throw RestErrors.internal(`Failed to list ${modelName} items`, { ...context, modelName, operation: 'list', listParams: props, }, error); } }; } /** * Creates a REST-aware queryIndex operation with general error handling. * * @internal * @template TTypes - Record of all available Amplify model types * @template T - Model name as string literal * @param rawModel - Original QueryFactory instance * @param modelName - Human-readable model name for error messages * @param context - Request context for error logging * @returns Function that performs queryIndex operation with REST error handling */ function createRestAwareQueryIndexOperation(rawModel, modelName, context) { return async (props) => { try { return await rawModel.queryIndex(props); } catch (error) { throw RestErrors.internal(`Failed to query ${modelName} index: ${props.queryField}`, { ...context, modelName, operation: 'queryIndex', queryField: props.queryField, indexParams: props, }, error); } }; } //# sourceMappingURL=restAware.js.map