This is a Spring Boot demo project that implements API documentation using OpenApi specification and API-first approach.
- Features
- Requirements
- Getting Started
- Implementation
This project's main features are:
- Generates the controllers and DTOs (as Java Records) based on the OpenAPI specification.
- Generates OpenAPI documentation for the API.
Note:
This readme file will focus on the OpenAPI documentation and API-first implementation. For more details about the other features of this project, please refer to the Spring Boot Template project that was used as a base for this project.
- Java 17
- Docker
- Docker Compose
This section provides a step-by-step guide on how to run the project.
- Clone the repository by executing the following command:
git clone https://github.com/andrecaiado/spring-boot-openapi.git
- Navigate into the
spec
directory:
cd spring-boot-openapi/spec
- Generate the code from the OpenAPI specification by executing the following command:
../mvnw clean compile
- Navigate to the
impl
directory:
cd ../impl
- Install the project dependencies by executing the following command:
../mvnw clean install
- Run the application by executing the following command:
../mvnw spring-boot:run
The API can be tested using the Swagger UI or Postman.
- The API documentation is available at http://localhost:8080/swagger-ui/index.html.
- The Postman collection is available here: spring-boot-template-rest-api.postman_collection.json
This section provides a brief explanation of the implementation details of the project.
To implement the API-first approach, the project is divided into the following modules:
- spec: Contains the OpenAPI specification file.
- impl: Contains the project's implementation, including the generated controllers and DTOs based on the OpenAPI specification.
The modules were created using IntelliJ. The steps to create a new module are:
- Right-click on the project's root directory.
- Select "New" -> "Module".
- Provide a name for the module and click "Finish".
After creating the impl
module, delete this module's src
folder and move the project's existing src
directory to the new module.
After creating the spec
module, one can delete this module's java
folder.
To update the pom.xml
file, move the dependencies and plugins from the project's root pom.xml
file to the impl
module's pom.xml
file.
This section provides a step-by-step guide on how to generate the controllers and DTOs based on the OpenAPI specification.
To generate the controllers and DTOs based on the OpenAPI specification, the openapi-generator-maven-plugin
plugin is used. The plugin configuration is defined in the spec
module's pom.xml file.
To have a better understanding of the plugin configuration, please refer to the openapi-generator-maven-plugin documentation.
Create a yaml
file in the spec
module's src/main/resources
directory. In this project, the OpenAPI specification is defined in the openapi.yaml file.
The OpenAPI specification file should contain the API's endpoints, request and response bodies, and other relevant information.
The OpenAPI specification file can be created manually or using a tool like Swagger Editor.
Please refer to the OpenAPI Specification documentation for more details on how to define the API's endpoints and models.
Type mappings and import mappings allow for types bound to the OpenAPI Specification's types to be remapped to a user's desired types.
- The
typeMappings
property is used to defines the user's target type for a given OpenAPI Specification type. - The
importMappings
informs the template of the type to be imported.
The typeMappings
and importMappings
properties are defined in the configuration
section of the plugin configuration. In this project, the typeMappings
and importMappings
properties are defined in the spec
module pom.xml file as shown below:
<configuration>
<typeMappings>
<typeMapping>OffsetDateTime=LocalDateTime</typeMapping>
<typeMapping>Pageable=org.springframework.data.domain.Pageable</typeMapping>
</typeMappings>
<importMappings>
<importMapping>LocalDateTime=java.time.LocalDateTime</importMapping>
<importMapping>Pageable=org.springframework.data.domain.Pageable</importMapping>
</importMappings>
</configuration>
The typeMappings
and importMappings
properties are optional. If they are not defined, the default mappings will be used.
In this project, we are mapping the OffsetDateTime type to LocalDateTime. This mapping is necessary because the OpenAPI specification uses OffsetDateTime for date-time fields however, the project uses LocalDateTime.
We also need to import the LocalDateTime class in the generated code, so we need to define the import mapping.
In this project, we are mapping the Pageable type to org.springframework.data.domain.Pageable. Because there is no Pageable type in the OpenAPI specification, we defined a custom type in the OpenAPI specification and so, we need to map it to the Spring Pageable type.
We also need to import the Pageable class in the generated code, so we need to define the import mapping.
To generate the controllers and DTOs based on the OpenAPI specification, execute the following command:
./mvnw clean compile
The plugin itself is defined to be triggered when the compile
phase is triggered.
After executing the command, the generated code will be available in the target
directory of the spec
module:
- Controllers:
target/generated-sources/openapi/src/main/java/com/example/springbootopenapi/controller
- DTOs:
target/generated-sources/openapi/src/main/java/com/example/springbootopenapi/dto
These locations were defined in the openapi-generator-maven-plugin
plugin configuration.
This section provides a brief explanation of how to use the generated code in the project.
In order to access the generated resources, the impl
module's pom.xml file should be updated to include the spec
module as a dependency.
First, we need to configure the dependency management in the main pom.xml file:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>spec</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
Then, we need to add the spec
module as a dependency in the impl
module's pom.xml file:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>spec</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
In the impl
module, create a new package to store the controllers. The controllers should then implement the interfaces that were generated based on the OpenAPI specification and that are available in the generated-sources
directory.
Note:
The above-mentioned interfaces were made available to the impl
module as it was explained in the previous section.
Example for the EmployeeController:
The EmployeeApi
interface contains the methods that should be implemented by the controller. The EmployeeController
class implements the EmployeeApi
interface and provides the implementation for the methods.
The example below shows the EmployeeController class after specifying that it implements the EmployeeApi interface and overriding the methods. All that is left to do is to implement the methods.
@RestController
@RequestMapping("/api/v1/employees")
public class EmployeeController implements EmployeeApi {
private final EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@Override
public ResponseEntity<String> deleteEmployeeById(Integer id) {
return null;
}
@Override
public ResponseEntity<List<EmployeeDto>> getAllEmployees(Pageable pageable) {
return null;
}
@Override
public ResponseEntity<EmployeeDto> getEmployeeById(Integer id) {
return null;
}
@Override
public ResponseEntity<EmployeeDto> saveEmployee(CreateEmployeeDto createEmployeeDto) {
return null;
}
@Override
public ResponseEntity<EmployeeDto> updateEmployee(Integer id, CreateEmployeeDto createEmployeeDto) {
return null;
}
}
The DTOs are available in the generated-sources
directory. To use the DTOs, import the classes in the controller classes.