Appearance
Error handling
This document provides a comprehensive overview of the API error handling strategy, including standard HTTP status codes, the structure of error responses, and guidance for troubleshooting common issues. A consistent and predictable error handling mechanism is crucial for client-side developers to build robust integrations.
This page should be read in conjunction with the API Reference for Ticket Endpoints.
HTTP Status Codes
The API uses standard HTTP status codes to indicate the success or failure of a request. Client applications should be prepared to handle the following codes.
| Status Code | Meaning | Usage Context |
|---|---|---|
| 200 OK | Success | Returned for successful GET and PUT operations. The response body contains the requested resource(s). |
| 201 Created | Resource Created | Returned when a new ticket is successfully created via POST /api/tickets. |
| 204 No Content | Successful Deletion | Returned when a ticket is successfully deleted via DELETE /api/tickets/{id}. The response body is empty. |
| 400 Bad Request | Client-Side Error | Returned when the request contains invalid data, such as missing required fields, malformed JSON, or invalid enum values. Spring's validation framework automatically generates this response. |
| 500 Internal Server Error | Server-Side Error | Triggered by unhandled exceptions within the application, such as a database connection failure or other unexpected RuntimeExceptions. The "resource not found" scenario currently falls into this category. |
Error Response Format
The application uses Spring Boot's default error response format, as no global exception handling (@ControllerAdvice) is currently implemented. The structure of the error response depends on the type of error.
Validation Errors (400 Bad Request)
When input validation fails (e.g., a required field is missing in a POST/PUT request), the API returns a 400 Bad Request with a detailed response body. This is triggered by the @Valid annotation in the TicketController.
Example JSON Response for Validation Error:
json
{
"timestamp": "2023-10-27T10:30:00.123Z",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"NotBlank.ticketRequest.title",
"NotBlank.title",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"ticketRequest.title",
"title"
],
"defaultMessage": "title",
"code": "title"
}
],
"defaultMessage": "must not be blank",
"objectName": "ticketRequest",
"field": "title",
"rejectedValue": "",
"bindingFailure": false,
"code": "NotBlank"
}
],
"path": "/api/tickets"
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
The most important part of this response for client developers is the errors array, which contains an object for each validation failure, specifying the field and the defaultMessage explaining the error.
General Server Errors (500 Internal Server Error)
For unhandled exceptions, such as failing to find a resource or database connectivity issues, the server returns a 500 Internal Server Error.
Example JSON Response for a "Not Found" Error:
json
{
"timestamp": "2023-10-27T10:35:15.987Z",
"status": 500,
"error": "Internal Server Error",
"message": "Ticket not found with id: 999",
"path": "/api/tickets/999"
}1
2
3
4
5
6
7
2
3
4
5
6
7
The message field contains the specific exception message thrown from the service layer, which is useful for debugging.
Common Error Scenarios
Understanding common error scenarios helps in building resilient client applications and diagnosing issues faster.
Invalid Ticket ID
When an endpoint like GET /api/tickets/{id}, PUT /api/tickets/{id}, or DELETE /api/tickets/{id} is called with an ID that does not exist in the database, the TicketService throws a RuntimeException.
Implementation Detail:
The service layer uses orElseThrow to handle cases where a ticket is not found.
java
// From: src/main/java/com/slalom/demo/ticketing/service/TicketService.java
public TicketResponse getTicket(Long id) {
log.info("Fetching ticket with ID: {}", id);
// This line throws a RuntimeException if the Optional is empty.
Ticket ticket = ticketRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Ticket not found with id: " + id));
return toResponse(ticket);
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Developer Note: This implementation currently results in a
500 Internal Server Error. A future improvement would be to create a customResourceNotFoundExceptionand map it to a404 Not Foundstatus code using a@ControllerAdvicefor more semantically correct error handling.
Missing or Invalid Request Body Fields
The createTicket and updateTicket endpoints validate the request body using jakarta.validation constraints, triggered by the @Valid annotation in the controller.
java
// From: src/main/java/com/slalom/demo/ticketing/controller/TicketController.java
@PostMapping
public ResponseEntity<TicketResponse> createTicket(@Valid @RequestBody TicketRequest request) {
log.info("REST: Creating new ticket");
TicketResponse response = ticketService.createTicket(request);
return new ResponseEntity<>(response, HttpStatus.CREATED);
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
If a required field (e.g., title) is null or empty, or if a field violates a constraint (e.g., an email address is malformed), the API will reject the request with a 400 Bad Request and a detailed error body as shown in the format section above.
Invalid Enum Values
Fields that map to an enum, such as status (TicketStatus), will cause an error if the provided string value does not match one of the defined enum constants (e.g., OPEN, IN_PROGRESS, RESOLVED, CLOSED). This applies to both the request body and request parameters.
For example, sending {"status": "PENDING"} in a request body or using /api/tickets?status=PENDING will result in a 400 Bad Request because PENDING is not a valid TicketStatus. The error is typically a HttpMessageNotReadableException handled by Spring, indicating a deserialization failure.
Database Connection Errors
If the application loses its connection to the MySQL database, any API call that requires data access will fail. This will result in a DataAccessException (or a subclass) being thrown by the Spring Data JPA repository layer. Since this is not explicitly handled, it will propagate and be caught by Spring Boot's default error handler, resulting in a 500 Internal Server Error. The application logs will contain the full stack trace, which is essential for diagnosing the root cause.
Troubleshooting
When an API call fails, use the HTTP status code and response body to diagnose the problem. For more detailed analysis, refer to the application logs.
For
400 Bad Requesterrors:- Inspect the
errorsarray in the JSON response. - Identify the
fieldthat failed validation and thedefaultMessageexplaining why. - Correct the client-side request payload to conform to the API's requirements. Refer to the Ticket Endpoints documentation for model schemas.
- For enum-related errors, ensure the value sent matches one of the allowed constants for
TicketStatusorTicketPriority.
- Inspect the
For
500 Internal Server Errorerrors:- Check the
messagefield in the JSON response. It often contains a specific server-side error message, such as"Ticket not found with id: 999". - If the message is generic (e.g., "Error processing request"), the primary source of information is the application logs on the server.
- Look for a full exception stack trace in the logs corresponding to the
timestampin the error response. This will pinpoint the exact line of code where the error occurred. - Common causes include database connectivity issues, unexpected null values, or other logic bugs.
- Check the
For persistent or complex server-side issues, consult the Operations Troubleshooting Guide.