Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

officiallysingh/problem-handler-web-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

19 Commits

Repository files navigation

Problem Handler Web Demo

Getting started

Docker compose

If you have docker installed, then simply run the application in docker profile by passing spring.profiles.active=docker as run time argument from your IDE. Depending on your current working directory in IDE, you may need to change spring.docker.compose.file=problem-handler-webflux-demo/compose.yml to spring.docker.compose.file=compose.yml in application-docker.properties

Make sure the host ports mapped in Docker compose file are available or change the ports and do the respective changes in database configurations application-docker.properties

Explicit Database configs

Update following properties with your PostgresDB configurations

spring.datasource.url=${POSTGRES_URL:jdbc:postgresql://localhost:5432/problem_web_db}
spring.datasource.username=${POSTGRES_USER:postgres}
spring.datasource.password=${POSTGRES_PASSWORD:admin}

Update following properties with your MongoDB configurations

spring.data.mongodb.uri=${MONGODB_URL:mongodb://localhost:27017/problem_web_db}

Run

Run the main class ProblemWebDemoApplication and access Swagger Swagger at http://localhost:8080/swagger-ui.html

Select Application from dropdown Select a definition

  • State management APIs are using MongoDB, to test database constraint violations.
  • Employee management APIs are using PostgresDB, to test database constraint violations.
  • Pet management APIs are validated by OpenAPI Specification.
  • Problem Demo APIs throws exceptions explicitly. Have a look at DemoProblemController
  • State and Employee management APIs are secured, so need to pass a JWT token in Authorization header. See the lock symbol against the API in Swagger

Click on Authorize button to pass the JWT Token. Use any valid JWT Token.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • Call the APIs providing invalid inputs to make it throw exception and have a look at response.
  • Set problem.debug-enabled=true in application.properties to get the message resolvers and set the messages in errors.properties to customize the error response attributes in response.
  • Test with setting problem.stacktrace-enabled=true and problem.cause-chains-enabled=true in application.properties to get Stacktrace and Cause in response.
  • Update help.html with any custom error description and follow the type url in error response to see the error description on help page.
  • Follow http://localhost:8080/problems/help.html to see the description of errors.

Examples

Following are example error responses in different scenarios. The error response attributes code, title and detail can be customized for each error by specifying the same in errors.properties file for different error keys which you can get by setting problem.debug-enabled=true in application.properties file

Constraint violations

Most common type of errors an application must handle

Jakarta Constraint violations error

Code

@Valid
@Getter
@Setter
public static final class UserRequest {
 @Size(min = 3, max = 10)
 private String name;
 @Size(min = 2, max = 5)
 private String designation;
 @NotNull
 @Valid
 private Address address;
}
@Getter
@Setter
@Valid
public static final class Address {
 @NotEmpty
 private String city;
 @NotEmpty
 private String state;
}

Request

curl -X 'POST' \
 'http://localhost:8080/problems/handler-constraint-violation' \
 -H 'accept: */*' \
 -H 'Content-Type: application/json' \
 -d '{
 "name": "a",
 "designation": "aaaaaaaaaaaaaaaaa",
 "address": {
 "city": "string"
 }
}'

Response

{
 "type": "http://localhost:8080/problems/help.html#constraint-violations",
 "title": "Bad Request",
 "status": 400,
 "detail": "Constraint violations has happened, please correct the request and try again",
 "instance": "/problems/handler-constraint-violation",
 "method": "POST",
 "timestamp": "2023年10月29日T16:41:59.876471+05:30",
 "code": "constraint-violations",
 "violations": [
 {
 "code": "400",
 "detail": "User name length should be between 3 and 10",
 "propertyPath": "name"
 },
 {
 "code": "400",
 "detail": "Address state name is required",
 "propertyPath": "address.state"
 },
 {
 "code": "400",
 "detail": "User designation length should be between 2 and 5",
 "propertyPath": "designation"
 }
 ]
}

PostgresDB Unique constraint violation error

Make following request two time, 2nd time the exception will be thrown.

Request

curl -X 'POST' \
 'http://localhost:8080/api/employees' \
 -H 'accept: */*' \
 -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' \
 -H 'Content-Type: application/json' \
 -d '{
 "name": "John Rambo",
 "dob": "1983-06-06"
}'

Response

{
 "type": "http://localhost:8080/problems/help.html#500",
 "title": "Internal Server Error",
 "status": 500,
 "detail": "Employee name must be unique, a record with given name already exists",
 "instance": "/api/employees",
 "method": "POST",
 "timestamp": "2023年10月29日T16:44:10.917194+05:30",
 "code": "500"
}

MongoDB Unique constraint violation error

Make following request two time, 2nd time the exception will be thrown.

Request

curl -X 'POST' \
 'http://localhost:8080/api/states' \
 -H 'accept: */*' \
 -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' \
 -H 'Content-Type: application/json' \
 -d '{
 "code": "HR",
 "name": "Haryana",
 "gstCode": "6"
}'

Response

{
 "type": "http://localhost:8080/problems/help.html#500",
 "title": "Internal Server Error",
 "status": 500,
 "detail": "State name must be unique",
 "instance": "/api/states",
 "method": "POST",
 "timestamp": "2023年10月29日T16:44:44.806613+05:30",
 "code": "500"
}

Invalid Query parameters

Request

curl -X 'GET' \
 'http://localhost:8080/problems/handler-invalid-query-strings?page=-1&size=1' \
 -H 'accept: */*'

Response

{
 "type": "http://localhost:8080/problems/help.html#constraint-violations",
 "title": "Bad Request",
 "status": 400,
 "detail": "Constraint violations has happened, please correct the request and try again",
 "instance": "/problems/handler-invalid-query-strings",
 "method": "GET",
 "timestamp": "2023年10月29日T14:51:37.889537+05:30",
 "code": "constraint-violations",
 "violations": [
 {
 "code": "400",
 "detail": "must be greater than or equal to 0",
 "propertyPath": "page"
 }
 ]
}

Invalid format error

Request

curl -X 'GET' \
 'http://localhost:8080/problems/handler-datetime-conversion?dateTime=2023-13-18T10%3A12%3A12Z' \
 -H 'accept: */*'

Response

{
 "type": "http://localhost:8080/problems/help.html#400",
 "title": "Bad Request",
 "status": 400,
 "detail": "Invalid date time value or format. Expected a valid date time in ISO format",
 "instance": "/problems/handler-datetime-conversion",
 "method": "GET",
 "timestamp": "2023年10月29日T16:05:09.953099+05:30",
 "code": "400",
 "propertyPath": "dateTime"
}

File upload max size exceeds error

Request

curl -X 'POST' \
 'http://localhost:8080/problems/uploadfile' \
 -H 'accept: */*' \
 -H 'Content-Type: multipart/form-data' \
 -F 'file=@Large_File.pdf;type=application/pdf'

Response

{
 "type": "http://localhost:8080/problems/help.html#400",
 "title": "Bad Request",
 "status": 400,
 "detail": "Upload file size exceeded the maximum allowed limit: 10485760B",
 "instance": "/problems/uploadfile",
 "method": "POST",
 "timestamp": "2023年10月29日T14:31:33.073971+05:30",
 "code": "400"
}

Spring framework thrown exceptions

Invalid Media type error

Request

curl -X 'POST' \
 'http://localhost:8080/problems/handler-json-body' \
 -H 'accept: */*' \
 -H 'Content-Type: application/xml' \
 -d '{
 "test": "string"
}'

Response

{
 "type": "http://localhost:8080/problems/help.html#415",
 "title": "Unsupported Media Type",
 "status": 415,
 "detail": "Media Type: application/xml Not Acceptable, Supported Media Types are: application/json",
 "instance": "/problems/handler-json-body",
 "method": "POST",
 "timestamp": "2023年10月29日T14:45:47.467268+05:30",
 "code": "415"
}

Method not allowed error

Request

curl -X 'POST' \
 'http://localhost:8080/problems/handler-datetime-conversion?dateTime=2023年04月18日T10%3A12%3A12Z' \
 -H 'accept: */*'

Response

{
 "type": "http://localhost:8080/problems/help.html#405",
 "title": "Method Not Allowed",
 "status": 405,
 "detail": "Requested Method: POST not allowed, allowed methods are: GET",
 "instance": "/problems/handler-datetime-conversion",
 "method": "POST",
 "timestamp": "2023年10月29日T16:15:08.916369+05:30",
 "code": "405"
}

Programmatically thrown exceptions

Any unhandled Throwable

Code

throw new IllegalArgumentException("Expected argument invalid", new IllegalStateException("Dummy cause"));

Request

curl -X 'GET' \
 'http://localhost:8080/problems/handler-throwable' \
 -H 'accept: */*'

Response

{
 "type": "http://localhost:8080/problems/help.html#500",
 "title": "Internal Server Error",
 "status": 500,
 "detail": "Expected argument invalid",
 "instance": "/problems/handler-throwable",
 "method": "GET",
 "timestamp": "2023年10月29日T14:49:40.998497+05:30",
 "code": "500"
}

Error with dynamic additional attributes

Code

Problem problem = Problems.newInstance("3456", "Bad Request", "Invalid request received, Please retry with correct input")
 .parameter("additional-attribute", "Some additional attribute").build();
throw Problems.throwAble(HttpStatus.BAD_REQUEST, problem);

Request

curl -X 'GET' \
 'http://localhost:8080/problems/throw-problem-with-additional-attribute' \
 -H 'accept: */*'

Response

{
 "type": "http://localhost:8080/problems/help.html#3456",
 "title": "Bad Request",
 "status": 400,
 "detail": "Invalid request received, Please retry with correct input",
 "instance": "/problems/throw-problem-with-additional-attribute",
 "method": "GET",
 "timestamp": "2023年10月29日T16:24:37.976724+05:30",
 "code": "3456",
 "additional-attribute": "Some additional attribute"
}

Multiple errors

Code

ApplicationException problemOne = Problems.newInstance("sample.problem.one").throwAbleChecked();
ApplicationProblem problemTwo = Problems.newInstance(AppErrors.REMOTE_HOST_NOT_AVAILABLE).detailArgs("http://some.remote.host.com").throwAble();
MultiProblem problems = Problems.ofExceptions(HttpStatus.MULTI_STATUS, problemOne, problemTwo);
Problem problemThree = Problems.newInstance("3456", "Bad Request", "Invalid request received, Please retry with correct input")
 .parameter("additional-attribute", "Some additional attribute").build();
problems.add(problemThree);
Exception exception = new IllegalStateException("Just for testing exception");
problems.add(exception);
Problem problem = Problems.newInstance("111", "Dummy", "Hardcode attributes broblem").build();
problems.add(problem);
throw problems;

Request

curl -X 'GET' \
 'http://localhost:8080/problems/throw-multiple-problems' \
 -H 'accept: */*'

Response

{
 "type": "http://localhost:8080/problems/help.html#207",
 "title": "Multi-Status",
 "status": 207,
 "detail": "Multi-Status",
 "instance": "/problems/throw-multiple-problems",
 "method": "GET",
 "timestamp": "2023年10月29日T16:22:53.363785+05:30",
 "code": "207",
 "errors": [
 {
 "code": "500",
 "title": "Internal Server Error",
 "detail": "Sample error message defined in 'errors.properties'"
 },
 {
 "code": "503",
 "title": "Service Unavailable",
 "detail": "Looks like something wrong with remote host: http://some.remote.host.com"
 },
 {
 "code": "3456",
 "title": "Bad Request",
 "detail": "Invalid request received, Please retry with correct input",
 "additional-attribute": "Some additional attribute"
 },
 {
 "code": "500",
 "title": "Internal Server Error",
 "detail": "Just for testing exception"
 },
 {
 "code": "111",
 "title": "Dummy",
 "detail": "Hardcode attributes broblem"
 }
 ]
}

OpenAPI Specification violation error

Request

curl -X 'POST' \
 'http://localhost:8080/api/pets' \
 -H 'accept: */*' \
 -H 'Content-Type: application/json' \
 -d '{
 "id": 0,
 "name": "string",
 "category": "string",
 "tags": [
 "string"
 ],
 "status": "AVAILABLE"
}'

Response

{
 "type": "http://localhost:8080/problems/help.html#constraint-violations",
 "title": "Bad Request",
 "status": 400,
 "detail": "Constraint violations has happened, please correct the request and try again",
 "instance": "/api/pets",
 "method": "POST",
 "timestamp": "2023年10月29日T16:06:18.335463+05:30",
 "code": "constraint-violations",
 "violations": [
 {
 "code": "400",
 "detail": "[Path '/id'] Numeric instance is lower than the required minimum (minimum: 1, found: 0)",
 "propertyPath": "id"
 }
 ]
}

Security error

Request

curl -X 'GET' \
 'http://localhost:8080/api/employees/1' \
 -H 'accept: */*'

Response

{
 "type": "http://localhost:8080/problems/help.html#401",
 "title": "Unauthorized",
 "status": 401,
 "detail": "Either Authorization header bearer token is missing or invalid",
 "instance": "/api/employees/1",
 "method": "GET",
 "timestamp": "2023年10月29日T16:08:40.466566+05:30",
 "code": "401"
}

About

Spring Web REST service for demonstrating problem handler

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /