Spring Boot Restful API Documentation With Swagger 2

How to use WebClient to call the API in Spring

How to use WebClient to call the API in Spring

In this quick tutorial, we will look at how to unit test services that use WebClient to call APIs in Spring

1. Overview

These days, we expect to call REST APIs in most of our services. Spring provides a few options for building a REST client, and WebClient is recommended.

In this quick tutorial, we will look at how to unit test services that use WebClient to call APIs.

2. Mocking

We have two main options for mocking in our tests:

3. Using Mockito

Mockito is the most common mocking library for Java. It's good at providing pre-defined responses to method calls, but things get challenging when mocking fluent APIs. This is because in a fluent API, a lot of objects pass between the calling code and the mock.

For example, let's have an EmployeeService class with a getEmployeeById method to fetch data via HTTP using WebClient:

public class EmployeeService {
 
    public Mono<Employee> getEmployeeById(Integer employeeId) {
        return webClient
                .get()
                .uri("http://localhost:8080/employee/{id}", employeeId)
                .retrieve()
                .bodyToMono(Employee.class);
    }
}

We can use Mockito to mock this:

@ExtendWith(MockitoExtension.class)
public class EmployeeServiceTest {
    
    @Test
    void givenEmployeeId_whenGetEmployeeById_thenReturnEmployee() {
 
        Integer employeeId = 100;
        Employee mockEmployee = new Employee(100, "Adam", "Sandler", 
          32, Role.LEAD_ENGINEER);
        when(webClientMock.get())
          .thenReturn(requestHeadersUriSpecMock);
        when(requestHeadersUriMock.uri("/employee/{id}", employeeId))
          .thenReturn(requestHeadersSpecMock);
        when(requestHeadersMock.retrieve())
          .thenReturn(responseSpecMock);
        when(responseMock.bodyToMono(Employee.class))
          .thenReturn(Mono.just(mockEmployee));
 
        Mono<Employee> employeeMono = employeeService.getEmployeeById(employeeId);
 
        StepVerifier.create(employeeMono)
          .expectNextMatches(employee -> employee.getRole()
            .equals(Role.LEAD_ENGINEER))
          .verifyComplete();
    }
 
}

As we can see, we need to provide a different mock object for each call in the chain, with four different when/thenReturn calls required. This is verbose and cumbersome. It also requires us to know the implementation details of how exactly our service uses WebClient, making this a brittle way of testing.

How can we write better tests for WebClient?

4. Using MockWebServer

MockWebServer, built by the Square team, is a small web server that can receive and respond to HTTP requests.

Interacting with MockWebServer from our test cases allows our code to use real HTTP calls to a local endpoint. We get the benefit of testing the intended HTTP interactions and none of the challenges of mocking a complex fluent client.

Using MockWebServer is recommended by the Spring Team for writing integration tests_._

4.1. MockWebServer Dependencies

To use MockWebServer, we need to add Maven dependencies for both okhttp and mockwebserver to our pom.xml:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.0.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>mockwebserver</artifactId>
    <version>4.0.1</version>
    <scope>test</scope>
</dependency>

4.2. Adding MockWebServer to our Test

Let's test our EmployeeService with MockWebServer:

public class EmployeeServiceMockWebServerTest {
 
    public static MockWebServer mockBackEnd;
 
    @BeforeAll
    static void setUp() throws IOException {
        mockBackEnd = new MockWebServer();
        mockBackEnd.start();
    }
 
    @AfterAll
    static void tearDown() throws IOException {
        mockBackEnd.shutdown();
    }
}

In the above JUnit Test class, the setUp and tearDown method takes care of creating and shutting down the MockWebServer.

The next step is to map the port of the actual REST service call to the MockWebServer's port.

@BeforeEach
void initialize() {
    String baseUrl = String.format("http://localhost:%s", 
      mockBackEnd.getPort());
    employeeService = new EmployeeService(baseUrl);
}

Now it's time to create a stub so that the MockWebServer can respond to an HttpRequest.

4.3. Stubbing a Response

Let's use MockWebServer's handy enqueue method to queue a test response on the web server:

@Test
void getEmployeeById() throws Exception {
    Employee mockEmployee = new Employee(100, "Adam", "Sandler", 
      32, Role.LEAD_ENGINEER);
    mockBackEnd.enqueue(new MockResponse()
      .setBody(objectMapper.writeValueAsString(mockEmployee))
      .addHeader("Content-Type", "application/json"));
 
    Mono<Employee> employeeMono = employeeService.getEmployeeById(100);
 
    StepVerifier.create(employeeMono)
      .expectNextMatches(employee -> employee.getRole()
        .equals(Role.LEAD_ENGINEER))
      .verifyComplete();
}

When the actual API call is made from the getEmployeeById(Integer employeeId) method in our _EmployeeService _class, MockWebServer will respond with the queued stub.

4.4. Checking a Request

We may also want to make sure that the MockWebServer was sent the correct HttpRequest.

MockWebServer has a handy method named takeRequest that returns an instance of RecordedRequest:

RecordedRequest recordedRequest = mockBackEnd.takeRequest();
  
assertEquals("GET", recordedRequest.getMethod());
assertEquals("/employee/100", recordedRequest.getPath());

With RecordedRequest, we can verify the HttpRequest that was received to make sure our WebClient sent it correctly_._

5. Conclusion

In this tutorial, we tried the two main options available to mock WebClient based REST client code.

While Mockito worked and may be a good option for simple examples, the recommended approach is to use MockWebServer.

As always, the source code for this article is available over on GitHub.

Spring Data REST Tutorial: Developing RESTful APIs with Ease

Spring Data REST Tutorial: Developing RESTful APIs with Ease

In this article, you will learn how to develop REST APIs with ease by using Spring Data REST and Spring Boot together. Throughout the article, you will scaffold a new Spring Boot application, create a JPA entity, and use Spring Data REST to provide some basic operations over it. Besides that, you will also learn how to validate the data your API is dealing with and how to secure the application.

In this article, you will learn how to develop REST APIs with ease by using Spring Data REST and Spring Boot together. Throughout the article, you will scaffold a new Spring Boot application, create a JPA entity, and use Spring Data REST to provide some basic operations over it. Besides that, you will also learn how to validate the data your API is dealing with and how to secure the application. If you need, you can check the final code developed throughout the article in this GitHub repository.

Introduction

Developing RESTful APIs is a task that most developers have faced at least once in their lives. Nowadays, with the increasing popularity of front-end frameworks like Angular, React, and Vue.js and with the mass adoption of smartphones, RESTful APIs became the most popular approach backend developers leverage to provide an interface for their applications. Knowing that, the Spring community, as you will see in this article, worked hard to build Spring Data REST, a framework that facilitates the life of developers while creating these APIs.

Spring Data REST builds on top of Spring Data repositories, analyzes your application’s domain model and exposes hypermedia-driven HTTP resources for aggregates contained in the model. — Spring Data REST
Together with Spring Boot, Spring Data REST enables developers to create production-ready APIs in a matter of minutes. Want some proof? Keep reading!
Spring Data REST builds on top of Spring Data repositories, analyzes your application’s domain model and exposes hypermedia-driven HTTP resources for aggregates contained in the model. — Spring Data REST## What You Will Build

To learn about Spring Data REST, you will build a simple RESTful API that exposes CRUD (Create, Retrieve, Update, and Delete) operations over an entity called Ad. The Ad entity, in this case, stands for advertisements and will be used to represent some product or service that a user is trying to sell. As such, your API will enable users to manipulate ads that hold information like title, owner, description, and price.

As mentioned before, while developing this RESTful API, you will learn how to:

  • provide an API with different basic operations over the entity created (Ad);
  • validate data;
  • and secure the API.
Prerequisites

To follow along with this article, you will need Java 8 or greater (up to Java 11) installed in your machine. If you don’t have Java yet, please, refer to the official documentation to install it in your development environment.

Besides Java, you will need some IDE (Integrated Development Environment) to help you in the development process. For that, there are a few great choices available out there (e.g., IntelliJ IDEA, Eclipse, and NetBeans). If you don’t have a preferred one yet, try using the community version of IntelliJ IDEA.

Scaffolding an App with Spring Boot

For starters, before diving into developing your RESTful API, you will need to scaffold your new application. To do so, open the Spring Initializr website in your browser and fill the presented form as follows:

  • provide an API with different basic operations over the entity created (Ad);
  • validate data;
  • and secure the API.

Then, on the Dependencies section, use the search for dependencies field to add five dependencies:

  • provide an API with different basic operations over the entity created (Ad);
  • validate data;
  • and secure the API.

After filling this page, click on the Generate Project button to download your new application. When done, you will have to extract the downloaded .zip file and move the extracted folder to a desired location.

If you are on a Unix-like operating system, you can also unzip the downloaded file with the following command:

unzip ads.zip


With that in place, use your IDE to open your new project. For example, if you are using IntelliJ IDEA, you can open the project by issuing the following command from the project root:

idea .


Creating RESTful APIs for JPA Entities with Spring Data REST

Now that you have scaffolded a new Spring Boot project and that you have opened it in your IDE, the first thing you will do is to create the JPA entity that you will expose with the help of Spring Data REST. To do so, create a new class called Ad inside the com.auth0.ads package, and add the following code to it:

// ./src/main/java/com/auth0/ads/Ad.java
package com.auth0.ads;

import lombok.EqualsAndHashCode;
import lombok.Getter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.math.BigDecimal;

@Entity
@Getter
@EqualsAndHashCode
public class Ad {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long id;

    public String owner;
    public String title;
    public String description;
    public BigDecimal price;

    protected Ad() {
    }

    public Ad(String owner, String title, String description, BigDecimal price) {
        this.owner = owner;
        this.title = title;
        this.description = description;
        this.price = price;
    }
}


As you can see from the code above, you are defining a new JPA @Entity called Ad to hold five different fields. Most of these fields are self-explanatory (their names should be enough for you to understand what they will hold). The only one that might need some explanation is the Long id field. As you can see, this field is marked with two annotations:

  • provide an API with different basic operations over the entity created (Ad);
  • validate data;
  • and secure the API.

After creating the Ad JPA entity, you will need to focus on creating a class that will allow you to interface with the database. Also, you will need to map the database operations into RESTful API endpoints so external clients can use them. Sounds like a lot of work? On the contrary! This is where Spring Data REST shines.

To achieve both things described in the last paragraph (map to the database and expose the operations in your API), you will need to do only one thing. You will need to create an interface called AdRepository (inside the com.auth0.ads package) and add the following code to it:

// ./src/main/java/com/auth0/ads/AdRepository.java
package com.auth0.ads;

import org.springframework.data.repository.PagingAndSortingRepository;

public interface AdRepository extends PagingAndSortingRepository<Ad, Long> {
}


That’s it! With this interface in place, you are ready to run your application and start issuing requests to it. Magic? Indeed it looks like so. However, what is happening here is that Spring Boot (a framework that is bound to the “convention over configuration” strategy) and Spring Data REST identify that you defined an interface that extends PagingAndSortingRepository and work together to create a bunch of endpoints for you.

If you check the JavaDocs of the PagingAndSortingRepository interface, you will see that this interface is an “extension of [CrudRepository](https://docs.spring.io/spring-data/data-commons/docs/current/api/org/springframework/data/repository/PagingAndSortingRepository.html "CrudRepository") to provide additional methods to retrieve entities using pagination and sorting.

More specifically, as described on the Core Concepts documentation of the Spring Data library, together, PagingAndSortingRepository and CrudRepository add the following methods to your application to allow it to manipulate your entities in a SQL database:

  • provide an API with different basic operations over the entity created (Ad);
  • validate data;
  • and secure the API.

Then, as you are using Spring Data REST, this library creates RESTful endpoints to exposes all the methods defined by PagingAndSortingRepository and CrudRepository.

To see all this magic in action, you can either press the play button in your IDE, or you can issue the following code in a terminal (as long as this terminal is pointing to the project root):

./gradlew bootRun


After the application starts executing (it will take a few seconds for it to be ready), you can start sending HTTP requests to its endpoints. To do so, you can use a graphical HTTP client like Postman, or you can open a new terminal and use a tool like curl. The next subsection will show you how to use curl to issue some requests to your new application. However, translating them to Postman or a similar client should not be a problem.

Spring Data REST builds on top of Spring Data repositories, analyzes your application’s domain model and exposes hypermedia-driven HTTP resources for aggregates contained in the model. — Spring Data REST### Issuing requests to the Spring Data REST endpoints

For starters, to confirm that your application is working as expected, you can issue the following request (you might need to run the command below in a new terminal or, as mentioned, you can use Postman):

# check if there are ads persisted
curl http://localhost:8080/ads


Running this command will make your API return all the ads persisted on the database (which will be none: "ads" : [ ]), and a few other things like:

  • provide an API with different basic operations over the entity created (Ad);
  • validate data;
  • and secure the API.

As you haven’t created any entity yet, the results won’t be very interesting. So, the next thing you can do is to issue a request to insert a new ad in your API:

# insert a new ad
curl -X POST -H "Content-Type:application/json" -d '{
    "owner": "me",
    "title": "My Car",
    "description": "Pretty awesome but, unfortunately, I have to sell it.",
    "price": 225599.99
}' http://localhost:8080/ads 


Issuing this command will output the details of the ad created (all the properties above) along with a link to the ad itself (self.href). If you use this link in a curl command, you will retrieve the details of the ad:

# retrieve the new ad
curl http://localhost:8080/ads/1


Now, if you run the command to see the list of persisted ads again:

curl http://localhost:8080/ads


You will see that the ads array includes your new ad and that the page properties (size, totalElements, etc.) are updated accordingly.

After that, if you want, you can delete the ad by issuing the following command:

curl -X DELETE http://localhost:8080/ads/1


Incredible, huh? After scaffolding your application, you just had to create two things (the Ad entity and the AdRepository interface), and you got a runnable RESTful API.

Data Validation

After seeing Spring Data REST in action, you might be thinking: “Ok, this library does facilitate creating RESTful APIs, but I need to validate the data before persisting it to the database. Will it be easy to validate my data?” The answer to that is yes! By using the Bean Validation Java specification, validating your data is as easy as adding some annotations to the fields in your JPA entity.

Spring Data REST builds on top of Spring Data repositories, analyzes your application’s domain model and exposes hypermedia-driven HTTP resources for aggregates contained in the model. — Spring Data REST> Spring Data REST builds on top of Spring Data repositories, analyzes your application’s domain model and exposes hypermedia-driven HTTP resources for aggregates contained in the model. — Spring Data REST
If you want some proof, open the Ad class and update its code to look like this:

// ./src/main/java/com/auth0/ads/Ad.java
package com.auth0.ads;

import lombok.EqualsAndHashCode;
import lombok.Getter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.math.BigDecimal;

@Entity
@Getter
@EqualsAndHashCode
public class Ad {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long id;

    @NotNull(message = "Who is the owner of this ad?")
    public String owner;

    @NotNull(message = "Please, inform a title for your ad.")
    @Size(min = 5, max = 140, message = "Titles must have between {min} and {max} characters.")
    public String title;

    @NotNull(message = "Please, inform a description for your ad.")
    @Size(min = 5, max = 500, message = "Titles must have between {min} and {max} characters.")
    public String description;

    @Min(message = "Price cannot be negative", value = 0)
    public BigDecimal price;

    protected Ad() {}

    public Ad(String owner, String title, String description, BigDecimal price) {
        this.owner = owner;
        this.title = title;
        this.description = description;
        this.price = price;
    }
}


On the new version of this entity, you are importing and using three new annotations:

  • provide an API with different basic operations over the entity created (Ad);
  • validate data;
  • and secure the API.

After updating the Ad class, you can rerun your application (by issuing ./gradlew bootRun or by pressing the start button on your IDE). When the app finishes booting, you can issue requests like the following to confirm that the restrictions are working:

# won't work, too few characters on the title property
curl -X POST -H "Content-Type:application/json" -d '{
    "owner": "me",
    "title": "Abc",
    "description": "Pretty awesome but, unfortunately, I have to sell it.",
    "price": 500
}' http://localhost:8080/ads 

# won't work, negative price
curl -X POST -H "Content-Type:application/json" -d '{
    "owner": "me",
    "title": "My Car",
    "description": "Pretty awesome but, unfortunately, I have to sell it.",
    "price": -10
}' http://localhost:8080/ads 

# won't work, no description
curl -X POST -H "Content-Type:application/json" -d '{
    "owner": "me",
    "title": "My Car",
    "price": 500
}' http://localhost:8080/ads 

# will work, all properties contain valid values
curl -X POST -H "Content-Type:application/json" -d '{
    "owner": "me",
    "title": "My Car",
    "description": "Pretty awesome but, unfortunately, I have to sell it.",
    "price": 500
}' http://localhost:8080/ads 


While issuing the invalid requests above (i.e., the first three), you will see that your app returns a response that looks like this:

{
  "timestamp": "2019-02-19T18:35:52.094+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction",
  "path":"/ads"
}


Although this response is sufficient for the calling client to understand that something went wrong, it doesn’t help to identify what the problem was. To fix that, you can create a new class called RestExceptionHandler inside the com.auth0.ads package and add the following code to it:

// ./src/main/java/com/auth0/ads/RestExceptionHandler.java
package com.auth0.ads;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.persistence.RollbackException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
    @ExceptionHandler(TransactionSystemException.class)
    protected ResponseEntity<List<String>> handleTransactionException(TransactionSystemException ex) throws Throwable {
        Throwable cause = ex.getCause();
        if (!(cause instanceof RollbackException)) throw cause;
        if (!(cause.getCause() instanceof ConstraintViolationException)) throw cause.getCause();
        ConstraintViolationException validationException = (ConstraintViolationException) cause.getCause();
        List<String> messages = validationException.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage).collect(Collectors.toList());
        return new ResponseEntity<>(messages, HttpStatus.BAD_REQUEST);
    }
}


With this class, you are creating and registering a global exception handler (ResponseEntityExceptionHandler) for your application. Then, inside this handler, you are defining a method that will catch instances of TransactionSystemException to unwrap the real problem (ex.getCause()). If the unwrapped exception is not an instance of RollbackException, then this method throws the underlying exception.

If the unwrapped problem is an instance of RollbackException, then this method unwraps the cause one more time (cause.getCause()). This time, the goal is to check if the second unwrap will result in an instance of ConstraintViolationException. If this is not the case, the unwrapped result is thrown. If this is the case, this method generates a list of messages to send back as a response.

After creating this exception handler, if you restart your app and issue bogus requests, you will get some friendly messages. For example, if you issue the following request:

curl -X POST -H "Content-Type:application/json" -d '{
    "owner": "me",
    "title": "My Car",
    "price": -10
}' http://localhost:8080/ads


You will get a list of messages saying that the “price cannot be negative” and to “please, inform a description for your ad.” Not to hard too validate your data in this stack, huh?

Securing Spring Data REST APIs

Cool, with a minimum amount of effort you were able to create a backend application that exposes a bunch of RESTful APIs and, in a couple of minutes, you were able to extend it with data validation. However, what about security? There is no production-ready RESTful API without security, right?

Luckily, adding a security layer to your current stack is not hard either. To do this, you will add the Spring Security framework on top of your application and will use it with Auth0 to generate and validate access tokens.

For starters, you will need to open the build.gradle file of your project and update it as follows:

// ... leave everything else untouched ...

dependencies {
    // ... leave the other dependencies untouched ...
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.2.RELEASE'
}


Here, you are making your project import two new dependencies. The first one is the Spring Boot extension for the Spring Security framework. The second one is a library that facilitates configuring OAuth (the authorization framework) which is used by Auth0.

After importing these new dependencies, you will have to:

  1. Add a couple of properties to the application.properties file to configure these dependencies.
  2. Create a class to define how the endpoints will be accessible.

However, before doing so, you will need to configure an Auth0 API to represent you RESTful backend.

Spring Data REST builds on top of Spring Data repositories, analyzes your application’s domain model and exposes hypermedia-driven HTTP resources for aggregates contained in the model. — Spring Data REST
After signing in (or signing up, if you didn’t have an Auth0 account yet), head to the APIs section of your Auth0 Dashboard and click on the Create API button. When you click on this button, Auth0 will show you a dialog where it will ask you for three things:

  • provide an API with different basic operations over the entity created (Ad);
  • validate data;
  • and secure the API.

After filling this form, click on the Create button. Then, back to your project, open the application.properties file and add the following to it:

# ./src/main/resources/application.properties
security.oauth2.resource.jwk.keySetUri=https://${YOUR-AUTH0-DOMAIN}/.well-known/jwks.json
security.oauth2.resource.id=https://ads-api


You will have to replace the ${YOUR-AUTH0-DOMAIN} placeholder with your Auth0 domain (e.g., blog-samples.auth0.com), and that you will have to make sure the resource.id property points to the identifier you used while registering your API.

Spring Data REST builds on top of Spring Data repositories, analyzes your application’s domain model and exposes hypermedia-driven HTTP resources for aggregates contained in the model. — Spring Data REST
With that in place, you will create a new class called SecurityConfig inside the com.auth0.ads package and add the following code to it:

// ./src/main/java/com/auth0/ads/SecurityConfig.java
package com.auth0.ads;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

@Configuration
@EnableResourceServer
public class SecurityConfig extends ResourceServerConfigurerAdapter {
    @Value("${security.oauth2.resource.id}")
    private String resourceId;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/ads/**").authenticated();
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(resourceId);
    }
}


The code for this class is quite simple. As you can see, you are using some Spring Boot annotations (like @Configuration and @Value) to make Spring configure this class while bootstrapping the app. Also, you are defining two configure methods to define how the Spring Security framework must behave. The first configure method is telling the framework that all calls to /ads/** must be authenticated. The second one is telling the ResourceServerSecurityConfigurer to use, as the resourceId, the value you added to the security.oauth2.resource.id property.

After creating your Auth0 API and making the changes described above, you can restart your application one more time and issue the following request:

curl http://localhost:8080/ads


This request (or any other aiming endpoints starting with /ads that do not carry an access token) will result in the following response:

{
  "error":"unauthorized",
  "error_description":"Full authentication is required to access this resource"
}


To be able to issue valid (or authenticated) requests, you will need an access token. The process of getting an access token will depend on what type of client you are dealing with. This is out of scope here but, if you are dealing with a SPA application (like those created with React, Angular, and Vue.js), you can check this article to learn how to proceed. If you are dealing with some other type of client (e.g., regular web application or native application), check the Auth0’s docs for more info.

Nevertheless, to see the whole thing in action, you can head back to your Auth0 Dashboard, open the API you just created, and move to the Test section. On this section, you will see a button called Copy Token that will provide you a temporary token that you can use to test your API.

So, click on this button and then use your client (or the terminal) to issue an HTTP request to your API with the test token:

# use the token copied to set the TOKEN variable
TOKEN=eyJ...DRA

# issue an authenticated HTTP request
curl -H 'Authorization: Bearer '$TOKEN http://localhost:8080/ads


If everything works as expected, you will be able to consume your API endpoints again. Awesome, right?

Conclusion

In this article, you learned about how easy it is to develop RESTful API with Spring Data REST and Spring Boot. More specifically, you started by using the Spring Initializr website to scaffold a new application. After that, you used Spring Data REST to expose API endpoints to manipulate a JPA entity. Then, in the end, you learned how to validate data and how to secure your API.

With that in place, you are ready to start developing production-ready, secure APIs with Spring Boot, Spring Data REST, and Auth0.

Spring Data REST builds on top of Spring Data repositories, analyzes your application’s domain model and exposes hypermedia-driven HTTP resources for aggregates contained in the model. — Spring Data REST
*Originally published by Bruno Krebs at *https://auth0.com

Learn More

Build a Basic App with Spring Boot and JPA using PostgreSQL

Build a Simple CRUD App with Spring Boot and Vue.js

Building A REST API With MongoDB, Mongoose, And Node.js

Creating RESTful APIs with NodeJS and MongoDB Tutorial

Understanding the basics of RESTful APIs

GraphQL Tutorial: Understanding Spring Data JPA/SpringBoot

Complete Java Masterclass

Complete Step By Step Java For Testers

Java Web Service Complete Guide - SOAP + REST + Buide App

Selenium WebDriver with Java - Basics to Advanced& Interview

Spring REST API Security Tutorial: Using OAuth2 + MySQL

Spring REST API Security Tutorial: Using OAuth2 + MySQL

Let's secure our Spring REST API with OAuth2 and MySQL. REST easy knowing your APIs are secure after this tutorial.

Let’s secure our Spring REST API with OAuth2 and MySQL. We will store user credentials in the MySQL database, and client credentials will be stored in the in-memory database. Every client has its own unique client ID.

To secure our REST API, we will have to do the following things:

  • Configure Spring Security and the database.

  • Configure the authorization server and resource server.

  • Get an access token and a refresh token.

  • Get a protected Resource (REST API) using an access token.

Before we start, let's look at some basic concepts related to Spring Security OAuth2.

You may also like: Spring Security Tutorial: Simple Authentication with Spring Boot.

OAuth2 Roles

Resource Owner

A resource owner is a person (like an end-user) in an application that owns the service or security policy.

Resource Server

This is the resource server hosting the protected resource or service.

Client Application

The client application is the application requesting access to resources stored on the resource server. The client application also obtains authorization from the resource owner.

Authorization Server

The authorization server is the server authorizing the client app to access the resources of the resource owner.

Application

Let's start to secure our REST API endpoints.

First, we need to enable Spring Security to add the security feature in the application. To configure and enable Spring Security, the @EnableWebSecurity annotation is used.

By using @EnableGlobalMethodSecurity, we can easily secure our methods with Java configurations. Global method security will activate  @PreFilter@PostFilter , @PreAuthorize, and the @PostAuthorize  annotations if we want to use them.

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired
  UserDetailsServiceImpl userDetailsService;
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
      .and().authorizeRequests().antMatchers("/oauth/token")
      .permitAll().anyRequest().authenticated();
  }
  @Bean
  public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setPasswordEncoder( bCryptPasswordEncoder() );
    provider.setUserDetailsService(userDetailsService);
    return provider;
  }
  @Bean
  public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
  }
  @Override
  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }
  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider());
  }
}

Note:

  • Here, WebSecurityConfigurerAdapter  is used to customize security implementation.

  • Endpoint /OAuth/tpken is used to request a token (access or refresh).

  • We inject a custom implementation of UserDetailsService in order to retrieve user details from the database.

  • We use the defined BCryptPasswordEncoder bean for password encoding.

Now, we need to configure the authorization server. The @EnableAuhtorizationServer  annotation enables an authorization server. AuthorizationServerConfigurerAdapter  implements the  AuthorizationServerConfigurer, which provides all the necessary methods to configure an Authorization server. It also contains information about registered clients and possible access to scopes and grant types.

@Configuration
@EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
  @Autowired
  @Qualifier("authenticationManagerBean")
  private AuthenticationManager authenticationManager;
  @Autowired
  UserDetailsService userDetailsService;
  @Override
  public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
  }
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
      .withClient("fooClientId").secret("secret")
      .authorizedGrantTypes("password", "authorization_code", "refresh_token").scopes("read","write")
      .autoApprove(true);
  }
  @Override
  public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).accessTokenConverter(defaultAccessTokenConverter())
      .userDetailsService(userDetailsService);
  }
  @Bean
  public TokenStore tokenStore(){
    return new JwtTokenStore(defaultAccessTokenConverter());
  }
  @Bean
  public JwtAccessTokenConverter defaultAccessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("123");
    return converter;
  }
}

Notes on the above configuration:

  • Registers a client with client-id ‘fooClientId’ and password ‘ secret’ and the roles and scope they are allowed.

  • Specifies authorized grant types (password, authorization_code, refresh_token).

  • Specifies the JwtTokenStore to store tokens.

Next, we need to configure the resource server. The @EnableResourceServer  annotation, applied on OAuth2 Resource Servers, enables a Spring Security filter that authenticates requests using an incoming OAuth2 token.

The class ResourceServerConfigurerAdapter implements the ResourceServerConfigure,  providing methods to adjust the access rules and paths that are protected by OAuth2 security.

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    private static final String RESOURCE_ID = "resource-server-rest-api";
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID);
    }
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();
    }
}

Next, we need to update the application.properties to configure the MySQL database. Create the user_management schema in MySQL and add the user table to store user credentials with roles.

spring.datasource.url = jdbc:mysql://localhost:3306/user_management
spring.datasource.username = root
spring.datasource.password = root

# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update

# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the entity manager)

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
server.port = 8080
Test Application

To access any secured REST API endpoint, first, we will have to get the access token. To get the access token, we will need to add an authorization header with client credentials and add the request body with user credentials in postman.

After receiving the access token and refresh token, we can access any secured REST API endpoints using access token. When the access token expired, the refresh token is used to get a new access token.

I have attached some of postmen request responses

getToken

getUser

addUser

You can refer to the whole project on GitHub.

Thank for reading. I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others

Originally published on dzone.com

Related Articles