Skip to content

wolfBonobo/interdimensional-service

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

5 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐ŸŒŒ Interdimensional Service

interdimensional-service is a Spring Boot microservice that wraps the Rick and Morty API using Hexagonal Architecture and CQRS (Query side).

The service goes beyond a simple proxy:

  • It introduces MongoDB-based read cache for Characters, Episodes and Locations.
  • External API calls are only made on cache miss.
  • Retrieved data is persisted in MongoDB for future queries.

If it looks overengineered for Rick & Mortyโ€ฆ
Yes. That is entirely intentional.


๐Ÿงฑ Architecture Overview

The project follows Hexagonal Architecture (Ports & Adapters) + CQRS (Query side).

๐ŸŸก Domain Layer

Pure business models, framework-agnostic.

  • Character
  • Episode
  • Location

No Spring, no persistence annotations.


๐Ÿ”ต Application Layer

Contains use cases and orchestration logic.

Inbound ports (what the app offers)

  • CharacterQueryPort
  • EpisodeQueryPort
  • LocationQueryPort
  • GetHealthQueryPort

Outbound ports (what the app needs)

  • External API access:
    • LoadCharacterPort
    • LoadEpisodePort
    • LoadLocationPort
  • Mongo cache access:
    • LoadCharacterCachePort
    • LoadEpisodeCachePort
    • LoadLocationCachePort

Application services

  • CharacterQueryService
  • EpisodeQueryService
  • LocationQueryService
  • GetHealthQueryService

Responsibilities:

  • Validate inputs
  • Normalize pagination
  • Query Mongo cache first
  • Fallback to external API
  • Persist results in Mongo
  • Throw explicit domain-level exceptions

Exceptions

  • CharacterNotFoundException
  • EpisodeNotFoundException
  • LocationNotFoundException

๐ŸŸฃ Infrastructure Layer

All technical details live here.

Inbound adapters (REST)

  • Controllers:
    • CharacterController
    • EpisodeController
    • LocationController
    • HealthController
  • DTOs:
    • CharacterResponseDto
    • EpisodeResponseDto
    • LocationResponseDto
  • Error handling:
    • RestExceptionHandler
    • ErrorResponse

Outbound adapters

HTTP (external API)
  • CharacterApiAdapter
  • EpisodeApiAdapter
  • LocationApiAdapter

Uses WebClient to consume the Rick & Morty API.

MongoDB (read cache)
  • Documents:
    • CharacterDocument
    • EpisodeDocument
    • LocationDocument
  • Repositories:
    • CharacterMongoRepository
    • EpisodeMongoRepository
    • LocationMongoRepository
  • Adapters:
    • CharacterMongoAdapter
    • EpisodeMongoAdapter
    • LocationMongoAdapter

Mongo acts as a read-through cache:

  1. Query Mongo
  2. If not found โ†’ query external API
  3. Persist result in Mongo
  4. Return domain model

๐Ÿ“ Project Structure

โ”œโ”€โ”€โ”€main
โ”‚   โ”œโ”€โ”€โ”€java
โ”‚   โ”‚   โ””โ”€โ”€โ”€com
โ”‚   โ”‚       โ””โ”€โ”€โ”€interdimensional
โ”‚   โ”‚           โ”‚   InterdimensionalServiceApplication.java
โ”‚   โ”‚           โ”‚
โ”‚   โ”‚           โ”œโ”€โ”€โ”€application
โ”‚   โ”‚           โ”‚   โ”œโ”€โ”€โ”€command
โ”‚   โ”‚           โ”‚   โ””โ”€โ”€โ”€query
โ”‚   โ”‚           โ”‚       โ”œโ”€โ”€โ”€exception
โ”‚   โ”‚           โ”‚       โ”‚       CharacterNotFoundException.java
โ”‚   โ”‚           โ”‚       โ”‚       EpisodeNotFoundException.java
โ”‚   โ”‚           โ”‚       โ”‚       LocationNotFoundException.java
โ”‚   โ”‚           โ”‚       โ”‚
โ”‚   โ”‚           โ”‚       โ”œโ”€โ”€โ”€ports
โ”‚   โ”‚           โ”‚       โ”‚   โ”œโ”€โ”€โ”€character
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚       CharacterQueryPort.java
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚       LoadCharacterCachePort.java
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚       LoadCharacterPort.java
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚
โ”‚   โ”‚           โ”‚       โ”‚   โ”œโ”€โ”€โ”€episode
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚       EpisodeQueryPort.java
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚       LoadEpisodeCachePort.java
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚       LoadEpisodePort.java
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚
โ”‚   โ”‚           โ”‚       โ”‚   โ”œโ”€โ”€โ”€health
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚       GetHealthQueryPort.java
โ”‚   โ”‚           โ”‚       โ”‚   โ”‚
โ”‚   โ”‚           โ”‚       โ”‚   โ””โ”€โ”€โ”€location
โ”‚   โ”‚           โ”‚       โ”‚           LoadLocationCachePort.java
โ”‚   โ”‚           โ”‚       โ”‚           LoadLocationPort.java
โ”‚   โ”‚           โ”‚       โ”‚           LocationQueryPort.java
โ”‚   โ”‚           โ”‚       โ”‚
โ”‚   โ”‚           โ”‚       โ””โ”€โ”€โ”€service
โ”‚   โ”‚           โ”‚               CharacterQueryService.java
โ”‚   โ”‚           โ”‚               EpisodeQueryService.java
โ”‚   โ”‚           โ”‚               GetHealthQueryService.java
โ”‚   โ”‚           โ”‚               LocationQueryService.java
โ”‚   โ”‚           โ”‚
โ”‚   โ”‚           โ”œโ”€โ”€โ”€domain
โ”‚   โ”‚           โ”‚   โ”œโ”€โ”€โ”€character
โ”‚   โ”‚           โ”‚   โ”‚       Character.java
โ”‚   โ”‚           โ”‚   โ”‚
โ”‚   โ”‚           โ”‚   โ”œโ”€โ”€โ”€episode
โ”‚   โ”‚           โ”‚   โ”‚       Episode.java
โ”‚   โ”‚           โ”‚   โ”‚
โ”‚   โ”‚           โ”‚   โ””โ”€โ”€โ”€location
โ”‚   โ”‚           โ”‚           Location.java
โ”‚   โ”‚           โ”‚
โ”‚   โ”‚           โ””โ”€โ”€โ”€infrastructure
โ”‚   โ”‚               โ”œโ”€โ”€โ”€adapters
โ”‚   โ”‚               โ”‚   โ”œโ”€โ”€โ”€in
โ”‚   โ”‚               โ”‚   โ”‚   โ””โ”€โ”€โ”€rest
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚   HealthController.java
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚
โ”‚   โ”‚               โ”‚   โ”‚       โ”œโ”€โ”€โ”€character
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚       CharacterController.java
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚       CharacterResponseDto.java
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚
โ”‚   โ”‚               โ”‚   โ”‚       โ”œโ”€โ”€โ”€episode
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚       EpisodeController.java
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚       EpisodeResponseDto.java
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚
โ”‚   โ”‚               โ”‚   โ”‚       โ”œโ”€โ”€โ”€error
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚       ErrorResponse.java
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚       RestExceptionHandler.java
โ”‚   โ”‚               โ”‚   โ”‚       โ”‚
โ”‚   โ”‚               โ”‚   โ”‚       โ””โ”€โ”€โ”€location
โ”‚   โ”‚               โ”‚   โ”‚               LocationController.java
โ”‚   โ”‚               โ”‚   โ”‚               LocationResponseDto.java
โ”‚   โ”‚               โ”‚   โ”‚
โ”‚   โ”‚               โ”‚   โ””โ”€โ”€โ”€out
โ”‚   โ”‚               โ”‚       โ”œโ”€โ”€โ”€events
โ”‚   โ”‚               โ”‚       โ”œโ”€โ”€โ”€http
โ”‚   โ”‚               โ”‚       โ”‚   โ”œโ”€โ”€โ”€character
โ”‚   โ”‚               โ”‚       โ”‚   โ”‚       CharacterApiAdapter.java
โ”‚   โ”‚               โ”‚       โ”‚   โ”‚       CharacterPageResponse.java
โ”‚   โ”‚               โ”‚       โ”‚   โ”‚       CharacterResponse.java
โ”‚   โ”‚               โ”‚       โ”‚   โ”‚
โ”‚   โ”‚               โ”‚       โ”‚   โ”œโ”€โ”€โ”€episode
โ”‚   โ”‚               โ”‚       โ”‚   โ”‚       EpisodeApiAdapter.java
โ”‚   โ”‚               โ”‚       โ”‚   โ”‚       EpisodePageResponse.java
โ”‚   โ”‚               โ”‚       โ”‚   โ”‚       EpisodeResponse.java
โ”‚   โ”‚               โ”‚       โ”‚   โ”‚
โ”‚   โ”‚               โ”‚       โ”‚   โ””โ”€โ”€โ”€location
โ”‚   โ”‚               โ”‚       โ”‚           LocationApiAdapter.java
โ”‚   โ”‚               โ”‚       โ”‚           LocationPageResponse.java
โ”‚   โ”‚               โ”‚       โ”‚           LocationResponse.java
โ”‚   โ”‚               โ”‚       โ”‚
โ”‚   โ”‚               โ”‚       โ”œโ”€โ”€โ”€jpa
โ”‚   โ”‚               โ”‚       โ””โ”€โ”€โ”€mongo
โ”‚   โ”‚               โ”‚           โ”œโ”€โ”€โ”€character
โ”‚   โ”‚               โ”‚           โ”‚       CharacterDocument.java
โ”‚   โ”‚               โ”‚           โ”‚       CharacterMongoAdapter.java
โ”‚   โ”‚               โ”‚           โ”‚       CharacterMongoRepository.java
โ”‚   โ”‚               โ”‚           โ”‚
โ”‚   โ”‚               โ”‚           โ”œโ”€โ”€โ”€episode
โ”‚   โ”‚               โ”‚           โ”‚       EpisodeDocument.java
โ”‚   โ”‚               โ”‚           โ”‚       EpisodeMongoAdapter.java
โ”‚   โ”‚               โ”‚           โ”‚       EpisodeMongoRepository.java
โ”‚   โ”‚               โ”‚           โ”‚
โ”‚   โ”‚               โ”‚           โ””โ”€โ”€โ”€location
โ”‚   โ”‚               โ”‚                   LocationDocument.java
โ”‚   โ”‚               โ”‚                   LocationMongoAdapter.java
โ”‚   โ”‚               โ”‚                   LocationMongoRepository.java
โ”‚   โ”‚               โ”‚
โ”‚   โ”‚               โ””โ”€โ”€โ”€configuration
โ”‚   โ”‚                       CorsProperties.java
โ”‚   โ”‚                       GlobalCorsConfig.java
โ”‚   โ”‚                       OpenApiConfig.java
โ”‚   โ”‚                       WebClientConfig.java
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€โ”€resources
โ”‚           application-dev.yml
โ”‚           application-prod.yml
โ”‚           application.yml
โ”‚
โ””โ”€โ”€โ”€test
    โ””โ”€โ”€โ”€java
        โ””โ”€โ”€โ”€com
            โ””โ”€โ”€โ”€interdimensional
                โ”œโ”€โ”€โ”€application
                โ”‚   โ””โ”€โ”€โ”€query
                โ”‚       โ””โ”€โ”€โ”€service
                โ”‚               CharacterQueryServiceTest.java
                โ”‚               EpisodeQueryServiceTest.java
                โ”‚               LocationQueryServiceTest.java
                โ”‚
                โ”œโ”€โ”€โ”€infrastructure
                โ”‚   โ””โ”€โ”€โ”€adapters
                โ”‚       โ”œโ”€โ”€โ”€in
                โ”‚       โ”‚   โ””โ”€โ”€โ”€rest
                โ”‚       โ”‚       โ”‚   HealthControllerTest.java
                โ”‚       โ”‚       โ”‚
                โ”‚       โ”‚       โ”œโ”€โ”€โ”€character
                โ”‚       โ”‚       โ”‚       CharacterControllerTest.java
                โ”‚       โ”‚       โ”‚
                โ”‚       โ”‚       โ”œโ”€โ”€โ”€episode
                โ”‚       โ”‚       โ”‚       EpisodeControllerTest.java
                โ”‚       โ”‚       โ”‚
                โ”‚       โ”‚       โ””โ”€โ”€โ”€location
                โ”‚       โ”‚               LocationControllerTest.java
                โ”‚       โ”‚
                โ”‚       โ””โ”€โ”€โ”€out
                โ”‚           โ”œโ”€โ”€โ”€character
                โ”‚           โ”‚       CharacterApiAdapterTest.java
                โ”‚           โ”‚
                โ”‚           โ”œโ”€โ”€โ”€episode
                โ”‚           โ”‚       EpisodeApiAdapterTest.java
                โ”‚           โ”‚
                โ”‚           โ””โ”€โ”€โ”€location
                โ”‚                   LocationApiAdapterTest.java
                โ”‚
                โ””โ”€โ”€โ”€integration
                        CharacterIntegrationTest.java
                        EpisodeIntegrationTest.java
                        LocationIntegrationTest.java

๐Ÿ“ก Exposed Endpoints

Characters

  • GET /api/v1/characters/{id}
  • GET /api/v1/characters?page=1&name=Rick&status=alive

Episodes

  • GET /api/v1/episodes/{id}
  • GET /api/v1/episodes?page=1&name=Pilot

Locations

  • GET /api/v1/locations/{id}
  • GET /api/v1/locations?page=1&name=Earth

Health

  • GET /health

๐Ÿงช Testing Strategy

  • Unit tests: Focus on application services and domain logic.
  • Controller slice tests: Use MockMvc to verify HTTP contracts.
  • Adapter tests: Verify correct mapping and error handling.
  • Integration tests (End-to-End): - Full context load (@SpringBootTest).
    • MockWebServer running on fixed ports to simulate the external API.
    • MongoDB (Testcontainers or Embedded) with explicit database cleanup between tests to ensure cache consistency.

๐Ÿงฐ Tech Stack

Component Version
Java 21
Spring Boot 3.3.x
Spring Web MVC REST
Spring WebFlux WebClient
Spring Data MongoDB Cache
JUnit 5 Testing
MockWebServer External API
Lombok Boilerplate
OpenAPI Swagger UI

๐Ÿš€ Run the Service

mvn clean verify
mvn spring-boot:run

๐Ÿ”ฎ Roadmap

  • Command side (CQRS)
  • Write persistence (JPA)
  • Observability
  • Metrics & tracing

๐Ÿ“„ License

MIT โ€” free to use across dimensions.

About

Interdimensional service using Rick & Morty API with hexagonal architecture.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages