Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Gianluca-X/DigitalMoney/llms.txt

Use this file to discover all available pages before exploring further.

Every microservice in the Digital Money House platform defines a @ControllerAdvice-annotated handler class that intercepts uncaught exceptions and converts them into well-structured HTTP responses. This centralised approach means you can write a single error-handling path in your client regardless of which service produced the error — the response shape and the mapping from exception type to HTTP status code are predictable and documented here.

Error Response Format

The accounts-service GlobalExceptionHandler returns a JSON object with four fields for every handled exception:
{
  "timestamp": "2024-01-15T10:30:00",
  "status": 404,
  "error": "Not Found",
  "message": "Account not found"
}
The auth-service and user-service handlers return a simpler plain-string body (the exception message) rather than a JSON envelope, but the HTTP status codes follow the same conventions described below.
When parsing error responses, always inspect the HTTP status code first. Fall back to reading the message field (accounts-service) or the raw response body (auth-service, user-service) to present a human-readable explanation.

Exception Types and HTTP Status Codes

Accounts-service (GlobalExceptionHandler)

ExceptionHTTP StatusMeaning
ResourceNotFoundException404 Not FoundResource (account, card, etc.) does not exist
BadRequestException400 Bad RequestInvalid request data or business rule violation
ConflictException409 ConflictState conflict (duplicate resource, etc.)
UnauthorizedException401 UnauthorizedCaller does not have permission for the action
AccessDeniedException (Spring Security)403 ForbiddenAccess denied by the security layer
InsufficientFundsException400 Bad RequestSender balance is too low for the transfer
CardAlreadyExistsException409 ConflictCard has already been registered on the account
CardNotFoundException404 Not FoundSpecified card does not exist
Exception (catch-all)500 Internal Server ErrorUnhandled server-side error
When the transfer controller catches InsufficientFundsException directly (i.e., before it reaches the global handler), it responds with 410 Gone rather than 400. This is an unconventional use of 410 — see the note below for details.

Auth-service (AuthExceptionHandler)

ExceptionHTTP StatusMeaning
UserNotFoundException400 Bad RequestNo user found matching the supplied email
InvalidVerificationCodeException400 Bad RequestEmail verification code is missing or incorrect
InvalidPasswordException400 Bad RequestPassword does not meet the required format
EmailNotVerifiedException403 ForbiddenLogin attempted before email address is verified
Exception (catch-all)500 Internal Server ErrorUnhandled server-side error

User-service (GlobalExceptionHandler)

ExceptionHTTP StatusMeaning
UnauthorizedException401 UnauthorizedCaller is not authorised to perform the action
EmailAlreadyRegisteredException400 Bad RequestDuplicate email during registration
UserNotFoundException404 Not FoundNo user found with the given ID or email
InvalidTokenException401 UnauthorizedToken is missing, malformed, or expired
DniAlreadyExistsException400 Bad RequestDNI (national ID) is already registered
AliasAlreadyExistsException400 Bad RequestChosen account alias is already in use
Exception (catch-all)500 Internal Server ErrorUnhandled server-side error

Notes on Specific Status Codes

410 Gone for Insufficient Funds

The cash-transfer endpoint (POST /accounts/{accountId}/transferences/money) catches InsufficientFundsException explicitly in the controller and returns 410 Gone:
} catch (InsufficientFundsException e) {
    return ResponseEntity.status(HttpStatus.GONE).body("Fondos insuficientes");
}
HTTP 410 is semantically intended for resources that have been permanently removed. Its use here is unconventional — it is a deliberate design choice in this codebase to make insufficient-funds failures easy to distinguish from generic 400 validation errors. Clients should treat a 410 response from a transfer endpoint as “insufficient balance”.
If the same InsufficientFundsException reaches the GlobalExceptionHandler (rather than the controller’s local catch block), it is mapped to 400 Bad Request instead. Clients should handle both 400 and 410 as potential insufficient-funds signals on transfer endpoints.

403 vs 401 for Authentication and Authorisation Failures

ScenarioStatus
No Authorization header present (accounts-service filter)401 Unauthorized
Malformed or expired JWT (accounts-service filter)401 Unauthorized
EmailNotVerifiedException (auth-service)403 Forbidden
AccessDeniedException from Spring Security (accounts-service)403 Forbidden
UnauthorizedException (user-service or accounts-service)401 Unauthorized
The practical distinction: 401 means the request lacked valid credentials and the client should re-authenticate; 403 means credentials were valid but the action is forbidden (e.g. attempting to access another user’s resource, or trying to log in before verifying your email).

409 Conflict for Duplicate Resources

Attempting to register a card that already exists, register an email that is already in use, or set an alias or DNI that is already taken all produce 409 Conflict (accounts-service) or 400 Bad Request (user-service, which uses BAD_REQUEST for duplicate email, DNI, and alias).

Example Error Responses

Insufficient funds (410) — transfer endpoint:
"Fondos insuficientes"
Resource not found (404) — accounts-service:
{
  "timestamp": "2024-01-15T14:22:10",
  "status": 404,
  "error": "Not Found",
  "message": "Account not found"
}
Email not verified (403) — auth-service:
"Email not verified"
Duplicate card (409) — accounts-service:
{
  "timestamp": "2024-01-15T14:25:00",
  "status": 409,
  "error": "Conflict",
  "message": "Card already exists"
}

Handling Errors in Client Code

A robust client should follow this pattern when consuming any Digital Money House endpoint:
  1. Check the HTTP status code before attempting to parse the body.
  2. For 4xx responses, parse the error body. Accounts-service returns a JSON object — read the message field. Auth-service and user-service return a plain string.
  3. For 5xx responses, surface a generic failure message and log the raw body for diagnostics. Do not retry 5xx responses automatically without exponential backoff.
  4. For 401, clear the stored token and redirect to the login screen — the session has expired or the token is invalid.
  5. For 403, inform the user they do not have permission for the action. Do not re-authenticate; the token itself is valid.
# Example: detect and handle a 401 in a shell script
response=$(curl -s -o /tmp/body.txt -w "%{http_code}" \
  http://localhost:8085/accounts/1/balance \
  -H 'Authorization: Bearer <token>')

if [ "$response" -eq 401 ]; then
  echo "Session expired. Please log in again."
elif [ "$response" -eq 403 ]; then
  echo "Access denied: $(cat /tmp/body.txt)"
elif [ "$response" -eq 200 ]; then
  cat /tmp/body.txt
else
  echo "Unexpected status $response: $(cat /tmp/body.txt)"
fi

Validation Errors

Several endpoints accept request bodies annotated with @Valid (e.g. user registration and update endpoints in the user-service). When a submitted field fails a Bean Validation constraint, Spring returns 400 Bad Request with a validation-error payload before the request even reaches controller logic. The response body in this case comes from Spring’s default MethodArgumentNotValidException handler, not from the custom GlobalExceptionHandler, and contains an errors array listing each failed field and constraint message.
During development, enable detailed validation error messages by setting server.error.include-binding-errors=always in your local application.properties. Never enable this in production as it may leak internal field names.

Build docs developers (and LLMs) love