Category: Spring REST

Swagger for documenting your Spring Boot REST Api

 

What Is Swagger?

Swagger is a set of open-source tools built around the OpenAPI Specification that can help you design, build, document and consume REST APIs.

Swagger  is mostly used as an open source project for describing and documenting RESTful APIs.  Swagger-UI an another tool which provides the capability of displaying the REST Api documentation in the browser.  Besides rendering documentation, Swagger UI allows other API developers or consumers to interact with the API’s resources without having any of the implementation logic in place.

The more details can be found through following documentations.

https://swagger.io/docs/ 

http://springfox.github.io/springfox/docs/current/

 

Springfox for Swagger

The Swagger 2 specification, which is known as OpenAPI specification has several implementations. Currently, Springfox that has replaced Swagger-SpringMVC (Swagger 1.2 and older) is popular for Spring Boot applications.

Continue reading “Swagger for documenting your Spring Boot REST Api”

Spring RestTemplate – exchange() method with GET and POST Requests

 

The exchange() method

Execute the HTTP method to the given URI template, writing the given HttpEntity to the request, and returns the response as ResponseEntity.

In below, i am going to show you some sample RestClient exchange requests with GET and POST HTTP methods.

 

 

GET request with No Request Parameters (With Headers)

In here the HTTP GET request is made without any query params (request params) and Basic Authentication header. Therefore by observing the below example, you can get an idea of how exchange method is used to send HTTP GET request without request parameters and headers.


public void findUserById()
{
String username = "chathuranga";
String password = "123";
Integer userId = 1;
String url = "http://localhost:8080/users/" + userId;
//setting up the HTTP Basic Authentication header value
String authorizationHeader = "Basic " + DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
HttpHeaders requestHeaders = new HttpHeaders();
//set up HTTP Basic Authentication Header
requestHeaders.add("Authorization", authorizationHeader);
requestHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE);
//request entity is created with request headers
HttpEntity<AddUserRequest> requestEntity = new HttpEntity<>(requestHeaders);
ResponseEntity<FindUserResponse> responseEntity = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
FindUserResponse.class
);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
System.out.println("response received");
System.out.println(responseEntity.getBody());
} else {
System.out.println("error occurred");
System.out.println(responseEntity.getStatusCode());
}
}

view raw

GET.java

hosted with ❤ by GitHub

 

 

GET request with Request Parameters (Query Params) and Headers

In here, the HTTP GET request is made with query parameters (request parameters) and Basic Authentication header. Therefore by observing the below example, you can get an idea of how exchange method is used to send HTTP GET request with request params and headers.

The generated request URL will be something like below. You can see that it includes the query params.

http://localhost:53793/users/1?name=chathuranga&email=chathuranga.t@gmail.com

 


public void findUserById()
{
String username = "chathuranga";
String password = "123";
Integer userId = 1;
String url = "http://localhost:&quot; + port + "/users/" + userId;
//setting up the HTTP Basic Authentication header value
String authorizationHeader = "Basic " + DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
HttpHeaders requestHeaders = new HttpHeaders();
//set up HTTP Basic Authentication Header
requestHeaders.add("Authorization", authorizationHeader);
requestHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE);
//request entity is created with request headers
HttpEntity<AddUserRequest> requestEntity = new HttpEntity<>(requestHeaders);
//adding the query params to the URL
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("name", "chathuranga")
.queryParam("email", "chathuranga.t@gmail.com");
ResponseEntity<FindUserResponse> responseEntity = restTemplate.exchange(
uriBuilder.toUriString(),
HttpMethod.GET,
requestEntity,
FindUserResponse.class
);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
System.out.println("response received");
System.out.println(responseEntity.getBody());
} else {
System.out.println("error occurred");
System.out.println(responseEntity.getStatusCode());
}
}

view raw

GET.java

hosted with ❤ by GitHub

 

 

POST request with Request Body and Headers

In here the HTTP POST request is made with valid request body and Basic Authentication header. Therefore by observing the below example, you can get an idea of how exchange method is used to send HTTP POST request with request body and headers.


public void httpPostRequestWithHeadersAndBody()
{
String url = "http://localhost:8080/users&quot;;
String username = "chathuranga";
String password = "123";
//set up the basic authentication header
String authorizationHeader = "Basic " + DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
//setting up the request headers
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
requestHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
requestHeaders.add("Authorization", authorizationHeader);
//setting up the request body
User user = new User();
user.setName("Sample User");
user.setUsername("user1");
user.setPassword("pass123");
//request entity is created with request body and headers
HttpEntity<User> requestEntity = new HttpEntity<>(user, requestHeaders);
ResponseEntity<UserResponse> responseEntity = restTemplate.exchange(
url,
HttpMethod.POST,
requestEntity,
UserResponse.class
);
if(responseEntity.getStatusCode() == HttpStatus.OK){
UserResponse user = responseEntity.getBody();
System.out.println("user response retrieved ");
}
}

view raw

post.java

hosted with ❤ by GitHub

 

Spring Framework: New Annotation for RequestMapping (@GetMapping, @PostMapping, @DeleteMapping, @PutMapping)

 

Spring Framework 4.3 has introduced few convenient annotations for HTTP Request Mapping based on the HTTP Request Method.

 

Old Way New Way
@RequestMapping(value = “/test”, method = RequestMethod.GET) @GetMapping(“/api/customers”)
@RequestMapping(value = “/test”, method = RequestMethod.POST) @PostMapping(“/api/create”)
@RequestMapping(value = “/test”, method = RequestMethod.PUT) @PutMapping(“/api/update”)
@RequestMapping(value = “/test”, method = RequestMethod.DELETE) @DeleteMapping(“/api/delete”)
@RequestMapping(value = “/test”, method = RequestMethod.PATCH) @PatchMapping(“/api/update”)

 

Here is the Sample code

@RestController
public class RestApiController
{
   @GetMapping(value = "/user")
   public String getMappingExample()
   {
      return "HTTP GET : Request Mapping";
   }

   @PostMapping(value = "/user")
   public String postMappingExample()
   {
      return "HTTP POST : Request Mapping";
   }

   @PutMapping(value = "/user")
   public String putMappingExample()
   {
      return "HTTP PUT : Request Mapping";
   }

   @DeleteMapping(value = "/user")
   public String deleteMappingExample()
   {
      return "HTTP DELETE : Request Mapping";
   }
}

Spring Framework: @PathVariable and @RequestParam

 

@PathVariable and @RequestParam are Spring MVC based annotations used for two different purposes. One is for accessing the path variable in the request URI and other one is for accessing the query param in query string.

 

@PathVariable

As name implies, @PathVariable annotation is used to access the variable value in the URI path.

POST   http://www.springbootdev.com/api/users/1/profile

@PostMapping("/api/users/{user_id}/profile")
public String getPathVariable(@PathVariable("user_id") Integer userId)
{
      //TODO implementation should goes here
}

 

Here you can see that user_id path variable is represented by userId variable. According to the sample URI request, the value of userId variable will be 1.

 

@RequestParam

@RequestParam annotation is used to access the query param in the query string. Then you might be wondering about “what is query string“.

 

What is query string?

Wikipedia says “On the World Wide Web, a query string is the part of a uniform resource locator (URL) containing data that does not fit conveniently into a hierarchical path structure. The query string commonly includes fields added to a base URL

http://www.springbootdev.com/departments/1/students?subject=IT&country=LK

In here,  subject=IT&country=LK can be identified as query string.

 

Here is the sample code for accessing above query string (subject and country)

@PostMapping("/departments/{department_id}/students")
public List<Student> getStudents(@RequestParam("subject") String subject,
                                 @RequestParam("country") String country) {
     //TODO implementation should goes here
}

 

Can we access both @RequestParam and @PathVariable in the same method?

 

Absolutely YES.  Please refer the sample code.

http://www.springbootdev.com/departments/1/students?subject=IT&country=LK

 

@PostMapping("/departments/{department_id}/students")
public List<Student> getStudents(
  @PathVariable("department_id") Integer departmentId,
  @RequestParam("subject") String subject,
  @RequestParam("country") String country) {

      //TODO implementation should goes here
}

 

Here you can see that path variable is represented by the departmentId and query params are represented  by subject and country variables.

 

JAX-RS  : @QueryParam and @PathParam

@PathVariable and @RequestParam  are Spring framework owned annotations. Therefore those annotations can be used only within the spring based web applications.

What will happen if you are building a RESTful web service without using Spring? Lets assume that we build JAX-RS web service. how do you access path variable and query parameters?  JAX-RS has the equivalent annotations for above spring based annotations and they do the same job.

@PathVariable (Spring based)  --- equivalent ---  @PathParam (JAX-RS)

@RequestParam (Spring based)  --- equivalent ---  @QueryParam (JAX-RS)

Enable Cross Origin Resource Sharing (CORS) for Spring REST Api

 

 

What is CORS (Cross Origin Resource Sharing)?

Cross Origin Resource Sharing is something that is declared by the w3c on communication between different domains. By CORS, communications between the same domain will be allowed to users and the communications that are cross-originated will be restricted to a few techniques. We can see this when we are talking to APIs mostly. The REST call may give us an error. This is because the server and the client sides are on different domains and the communication between them are restricted by CORS rules.

If you want to learn more,please do a google search. you can find a lot of resources related to CORS and their importance. 

The Spring has given a nice explanation and that can accessed with following URL.

https://spring.io/understanding/CORS

 

Importance of CORS

The importance of the CORS implementation comes with the security aspects. It blocks the calls made by unknown domains and keeps the paths open only to the known domains. So the security is ensured despite the attacking requests.

 

Continue reading “Enable Cross Origin Resource Sharing (CORS) for Spring REST Api”

Securing Spring REST Api with Spring Security and JWT (Json Web Token)

In this article, i am going to demonstrate how to user JWT (Json Web Token) Authentication with Spring boot and Spring Security.  In here, i am not going to discuss the basic theory and details about the JWT and you can search google and find a lot of resources related to that.

GitHub URL :-  https://github.com/chathurangat/spring-rest-jwt-auth-example 

I will update a screenshot of my project structure to get an idea of project structure and class/files locations. Don’t worry! This is just to get an idea. We will be doing everything one by one as we are proceeding.

Screen Shot 2017-07-17 at 3.07.00 PM

Before starting with the development, i will briefly give you an idea about the classes that we are going to develop in this article.
First step is to create spring boot web project. This can be easily created with Spring Initializer (https://start.spring.io/). Remember to add web and spring security dependencies for your app.  In addition to that, it is important to add JWT dependency.

Required dependencies in pom.xml

<?xml version="1.0" encoding="UTF-8"?>
	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
        </dependency>

	</dependencies>

Then create a JwtService class as below. The JwtService class will be used for following two purposes.

  • Generate JWT token based on username upon successful user login.
  • Validate /Authenticate JWT token (user send along with every request)  and extract user information from the token.

JwtService.java 


import com.chathuranga.rest.jwt.auth.SecretKeyProvider;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.util.Date;

import static java.time.ZoneOffset.UTC;

@Component
public class JwtService {

    private static final String ISSUER = "com.chathuranga.examples";

    @Autowired
    private SecretKeyProvider secretKeyProvider;

    public String generateToken(String username) throws IOException, URISyntaxException {
        byte[] secretKey = secretKeyProvider.getKey();
        Date expiration = Date.from(LocalDateTime.now(UTC).plusHours(2).toInstant(UTC));
        return Jwts.builder()
                .setSubject(username)
                .setExpiration(expiration)
                .setIssuer(ISSUER)
                .signWith(SignatureAlgorithm.HS512, secretKey)
                .compact();
    }

    public String verifyToken(String token) throws IOException, URISyntaxException {
        byte[] secretKey = secretKeyProvider.getKey();
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        //returning authenticated/verified username
        return claims.getBody().getSubject();
    }
}

Now we need to create a LoginController for authenticating users with their credentials (username and password) and issue JWT token (using JwtService) upon successful authentication

LoginController.java


import com.chathuranga.rest.jwt.auth.exception.FailedToLoginException;
import com.chathuranga.rest.jwt.auth.model.AuthenticationResponse;
import com.chathuranga.rest.jwt.auth.model.UserCredentials;
import com.chathuranga.rest.jwt.auth.service.UserAuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
public class LoginController {

    @Autowired
    private UserAuthenticationService authenticationService;

    @ResponseStatus(HttpStatus.OK)
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public AuthenticationResponse userLogin(@RequestBody UserCredentials userCredentials) throws FailedToLoginException {

        if (userCredentials == null || (userCredentials.getUsername() == null || userCredentials.getPassword() == null)) {
            throw new FailedToLoginException("Missing login credentials ");
        }

        String token = authenticationService.authenticateUser(userCredentials.getUsername(), userCredentials.getPassword());

        if (token != null) {
            AuthenticationResponse authenticationResponse = new AuthenticationResponse();
            authenticationResponse.setUsername(userCredentials.getUsername());
            authenticationResponse.setToken(token);
            return authenticationResponse;
        }
        throw new FailedToLoginException(String.format(" unable to authenticate user [%s] ", userCredentials.getUsername()));
    }
}

Here is the Implementation of the UserAuthenticationService class. For the demonstration purpose i have hard coded two user credentials. But in production environment, you need to implement JPA based user repository or some other mechanism like LDAP or OpenId.

UserAuthenticationService.java


import com.chathuranga.rest.jwt.auth.exception.FailedToLoginException;
import com.chathuranga.rest.jwt.auth.exception.JwtAuthenticationException;
import com.chathuranga.rest.jwt.auth.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;

@Component
public class UserAuthenticationService {

    @Autowired
    private JwtService jwtService;

    @Autowired
    private UserService userService;

    public String authenticateUser(String username, String password) throws FailedToLoginException {
        boolean isAuthenticated = false;
        if (username.equals("chathuranga") && password.equals("test123")) {
            isAuthenticated = true;
        } else if (username.equals("bob") && password.equals("test123")) {
            isAuthenticated = true;
        }

        if (isAuthenticated) {
            try {
                return jwtService.generateToken(username);
            } catch (URISyntaxException | IOException e) {
                throw new FailedToLoginException(e.getMessage());
            }
        }
        throw new FailedToLoginException(String.format("unable to authenticate user [%s]", username));
    }

    public User authenticateToken(String jwtToken) throws JwtAuthenticationException {

        try {
            String username = jwtService.verifyToken(jwtToken);
            List<String> userRoles = userService.getUserRoles(username);

            User user = new User();
            user.setUsername(username);
            user.setUserRoles(userRoles);
            return user;
        } catch (IOException | URISyntaxException e) {
            throw new JwtAuthenticationException(e.getMessage(), e);
        }
    }
}

One more thing! I forgot to show you the implementation of AuthenticationResponse class.
This is just a POJO class implemented to return the successful authentication response back to the client. Here is the implementation. You will notice that we are returning username and JWT token back to the client.

AuthenticationResponse.java


package com.chathuranga.rest.jwt.auth.model;

public class AuthenticationResponse {

    private String username;
    private String token;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

Once this LoginController is fully developed, we should be able to authenticate users with their credentials. We have hardcoded few user credentials. I am going to test the user authentication with those credentials using Postman tool.

Username: chathuranga
Password: test123

Username: bob
Password: test123

Here is my Postman request.

Screen Shot 2017-07-17 at 4.33.39 PM

Here is the response retrieved. You can see that i am getting the username and JWT token as the response.

Now we have the JWT token. So we can use this token to show our authenticity.

Accessing Secured Api

Please refer the below secured controller. It has two methods to support for two endpoint URLs.

1. /api/admin/hello – this can be accessed only by users with ROLE_ADMIN
2. /api/user/hello – this can be accessed only by users with ROLE_USER


package com.chathuranga.rest.jwt.controller;

import org.springframework.http.HttpMethod;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/api")
public class WelcomeController {

    @Secured("ROLE_ADMIN")
    @RequestMapping(path = "/admin/hello", method = RequestMethod.GET)
    public String helloAdminController() {
        String loggedUserName = SecurityContextHolder.getContext().getAuthentication().getName();

        return "Hello Admin " + loggedUserName;
    }

    @Secured("ROLE_USER")
    @RequestMapping(path = "/user/hello", method = RequestMethod.GET)
    public String helloUserController() {

        String loggedUserName = SecurityContextHolder.getContext().getAuthentication().getName();

        return "Hello User " + loggedUserName;
    }
}

Please refer the following Postman screenshot.

Screen Shot 2017-07-17 at 3.03.31 PM

Spring Security Related Configurations and Implementation Classes

SecurityConfig.java


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthFilter authFilter;

    @Autowired
    private JwtAuthenticationProvider authenticationProvider;

    @Autowired
    private JwtAuthenticationEntryPoint authenticationEntryPoint;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/login");

        http.authorizeRequests()
                .antMatchers("/login")
                .permitAll()
                .antMatchers("/api/**")
                .authenticated()
                .and()
                .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint);
    }
}

  • Here we have used a custom authentication provider called JwtAuthenticationProvider. It will be used to authenticate users , based on JWT token.  
  • We have disabled the CSRF token validation for URL  /login.  
  • Any request coming to /login will be permitted and any request coming to URL /api/** should be authenticated.
  • We have created a custom Filter (JwtAuthFilter) and it will be applied before executing UsernamePasswordAuthenticationFilter

Any authentication related exception will be handled using the custom authentication entry point provided.(That is JwtAuthenticationEntryPoint)

JwtAuthFilter.java

This filter will be used to capture the JWT token sent by the users through Authorization header. This will find the JWT token in the request header and set it in the Authentication object before executing the UsernamePasswordAuthenticationFilter provided by the Spring security.

(The filter creates an instance of  JwtAuthToken class with token retrieved and set it as  the current Authentication object for the request)

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class JwtAuthFilter implements Filter
{

    @Override
    public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
    {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        String authorization = servletRequest.getHeader("Authorization");

        if (authorization != null)
        {
            JwtAuthToken token = new JwtAuthToken(authorization.replaceAll("Bearer ", ""));
            SecurityContextHolder.getContext().setAuthentication(token);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy()
    {

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {

    }
}

 

JwtAuthenticationProvider.java

import com.chathuranga.rest.jwt.auth.model.User;
import com.chathuranga.rest.jwt.auth.service.UserAuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

@Component
public class JwtAuthenticationProvider implements AuthenticationProvider
{

    @Autowired
    private UserAuthenticationService authenticationService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException
    {
      User user =  authenticationService.authenticateToken((String) authentication.getCredentials());
      return new JwtAuthenticatedUserToken(user.getUsername(),user.getUserRoles());
    }

    /*
     Returns true if this AuthenticationProvider supports the indicated Authentication object.
     */
    @Override
    public boolean supports(Class<?> aClass)
    {
        return JwtAuthToken.class.equals(aClass);
    }
}

The JwtAuthenticationProvider receives the Authentication instance set on the SecurityContext, which in our case is the JwtAuthToken we set using the JwtAuthFilter. This token is then verified using the JwtService. If the token is valid, we return a JwtAuthenticatedUserToken (username and ACL – Access Control List) or throw an AuthenticationException if it is invalid. Any authentication related exception (an instance of AuthenticationException) will be handled by JwtAuthenticationEntrypoint.

JwtAuthenticationEntryPoint.java

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;

import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint
{
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e)
            throws IOException, ServletException {
        httpServletResponse.setStatus(SC_FORBIDDEN);
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);

        String message;
        if(e.getCause() != null) {
            message = e.getCause().getMessage();
        } else {
            message = e.getMessage();
        }
        byte[] body = new ObjectMapper()
                .writeValueAsBytes(Collections.singletonMap("error", message));
        httpServletResponse.getOutputStream().write(body);
    }
}