- Project Overview
- Google OAuth2
- ElasticSearch Configuration
- Spring Cloud Contract (SCC)
- TestContainers
- OpenAPI
- Running the Project
- Integration Testing
Full project consists of two microservices:
- localhost:8080 - tourRegistration-service
- localhost:8081 - travelAgency-OAuth2-client
This microservice implements CRUD functionality using advanced technologies and practices such as OAuth2, OpenID, ElasticSearch, and RabbitMQ.
The tour registration service, in OpenID terminology, is a resource server. Access to some of its functions is only available with an access token (opaque token). To obtain an access token, the end user must either use the HTML page or directly access the endpoints of the travel-agency-client. The Spring framework handles the logic of redirecting the user to the Google authorization page, where the user voluntarily provides their data. Spring uses internal tools to store user data, which will be transmitted in requests to the tourRegistration-service.
Token validation is implemented in the class that implements the OpaqueTokenIntrospector
interface.
OAuth2 authentication is enabled in the configuration class through the SecurityFilterChain bean.
- GoogleTokenIntrospector (
src/main/java/yermakov/oleksii/tourregistrationservice/config/GoogleTokenIntrospector.java
) - SpringSecurityConfig (
src/main/java/yermakov/oleksii/tourregistrationservice/config/SpringSecurityConfig.java
)
ElasticSearch enables efficient and intelligent text data search. Its configuration is defined in a directory with two files:
- tours_index_mappings.json: Index mapping settings. The index is set to strict mapping, so unauthorized changes will result in errors.
- tours_index_settings.json: Index settings configuration, currently only defining a custom analyzer. In addition to strict mapping validation, the project logic defines its own index validation during startup by comparing JSON files (defined in the project body and obtained from the index itself).
The Elasticsearch functionality is implemented in the TourSearchService
interface (src/main/java/yermakov/oleksii/tourregistrationservice/service/TourSearchService.java).
The TourSearchServiceImpl
class implements this interface (src/main/java/yermakov/oleksii/tourregistrationservice/service/TourSearchServiceImpl.java).
In this class, I used ElasticsearchOperations
as the DAO class, but ElasticsearchRepository
can also be used.
Spring Cloud Contract (SCC) details: Contracts are designed to document the format of API requests and responses. For each method, I wrote a Groovy contract. Besides documenting, SCC allows generating integration tests. This happens during maven install, generating and running the tests. All necessary test settings should be done in the base class.
- Groovy contract files (
src/test/resources/contracts
). - Base test class (
src/test/java/yermakov/oleksii/tourregistrationservice/contractVerifier/BaseContractTest.java
).
A great way to use test Docker containers. In the base class for SCC tests, I define all necessary external dependencies for successful testing.
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(
"postgres:16"
).withReuse(true);
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
registry.add("spring.flyway.url", postgres::getJdbcUrl);
registry.add("spring.flyway.user", postgres::getUsername);
registry.add("spring.flyway.password", postgres::getPassword);
}
- Base test class (
src/test/java/yermakov/oleksii/tourregistrationservice/contractVerifier/BaseContractTest.java
).
The project was developed with the specification-first practice, meaning specifications were written first. This allowed defining a single source of truth and generating initial code for APIs and models. For correct generation, I used Mustache templates. I used the generated code as a template and manually supplemented it, although there is an approach to make all changes in the templates and constantly regenerate them.
- OpenApi specification (
api-specs/tourRegistration.yaml
) - API specification in
src/main/java/yermakov/oleksii/tourregistrationservice/api/TourCrudApi.java
. - Model definitions in
src/main/java/yermakov/oleksii/tourregistrationservice/model/TourDto.java
. - Mustache templates for generating API code (
src/main/resources/templates/openapi-templates
).
cd docker
docker-compose up -d
mvn spring-boot:run
mvn clean install