Satélite API implements structured error handling through GraphQL exceptions and a custom error filter. This ensures consistent error responses across the API and provides meaningful error information to clients.
The API uses GraphQLException to throw errors that are properly formatted in GraphQL responses. This pattern is used consistently throughout the codebase.
All errors are logged with full exception details for debugging:
_logger.LogError("Exception: {ex}", error);
2
Custom Exception Handling
Special handling for SateliteException domain exceptions:
if (ex is SateliteException de){ return ErrorBuilder .FromError(error) .SetMessage(de.Message) .SetCode(de.Code ?? "DOMAIN_ERROR") .SetExtension("status", de.Status) .Build();}
3
Default Error Passthrough
Other exceptions are passed through as-is:
return error;
The commented code shows an alternative implementation that could hide error details in production:
//return ErrorBuilder// .FromError(error)// .SetMessage(_env.IsDevelopment() // ? (ex?.Message ?? error.Message) // : "Se ha producido un error inesperado")// .SetCode("UNEXPECTED_ERROR") // .Build();
The API defines custom exceptions for domain-specific errors:
Example: SateliteException
public class SateliteException : Exception{ public string Code { get; set; } public int Status { get; set; } public SateliteException(string message, string code, int status = 400) : base(message) { Code = code; Status = status; }}
Usage:
if (invalidCondition){ throw new SateliteException( "Invalid operation", "INVALID_OPERATION", 400 );}
Here are the standard error codes used throughout the API:
Error Code
Description
USUARIODTO_NOT_FOUND
User not found
PRODUCTODTO_NOT_FOUND
Product not found
CENIZADTO_NOT_FOUND
Ceniza record not found
PRODUCTODETALLEDTO_NOT_FOUND
Product detail not found
APISRIDTO_NOT_FOUND
SRI API record not found
RolesDTO_NOT_FOUND
Role not found
PermisoDTO_NOT_FOUND
Permission not found
RolPermisoDTO_NOT_FOUND
Role-permission mapping not found
IndSupPqrDTO_NOT_FOUND
PQR not found
IndSupSolpedDTO_NOT_FOUND
Solped not found
CENIZA_NOT_FOUND
Ceniza not found (mutation variant)
DOMAIN_ERROR
Generic domain error
FAIL
Generic failure
Consistency: Always use the same error code for the same type of error across the API. This makes it easier for clients to handle errors programmatically.
public async Task<ProductoDTO> GetProductoById(int id){ ProductoDTO producto = await _productoRepository.GetById(id); if (producto is null) { throw new GraphQLException( new Error("ProductoDTO NOT_FOUND.", "PRODUCTODTO_NOT_FOUND")); } return producto;}
public async Task<IEnumerable<IndAntAprobacionDTO>> GetAllAprobacionesTodas(){ try { return await _indAntAprobacionRepository.GetAll(); } catch (Exception ex) { throw new GraphQLException( new Error("FAIL.", "FAIL " + ex.Message)); }}
Recommendation: Use Pattern 2 (direct validation) for simple null checks, and Pattern 1 (try-catch with fallback) when database operations might throw specific exceptions that need to be handled differently.