Skip to content

NullPoint3rDev/resilient-bff

Repository files navigation

Resilient BFF

A Backend-for-Frontend (BFF) service that aggregates downstream APIs with resilience patterns, observability, and graceful degradation. Built with Spring Boot 3, WebFlux, and Resilience4j.

Java Spring Boot Reactive Gradle Docker License


Features

  • Aggregation API — Single /api/dashboard endpoint that combines user and product data from two backend services.
  • Resilience4j — Circuit breaker and retry per downstream service; configurable via application.yml.
  • Fallback responses — When a backend is down or the circuit is open, the BFF returns partial data (empty user or empty products) instead of failing the whole request.
  • Reactive stack — Spring WebFlux and WebClient for non-blocking I/O and backpressure.
  • Observability — Spring Boot Actuator, Prometheus metrics, and Grafana-ready dashboards; optional Docker Compose stack for Prometheus + Grafana.
  • Tests — Unit tests for services (mocked WebClient) and integration tests for the BFF controller (@WebFluxTest, WebTestClient).
  • One-command rundocker compose up -d --build runs BFF, mock backends, Prometheus, and Grafana.

Architecture

                    ┌─────────────┐
                    │   Client    │
                    └──────┬──────┘
                           │ GET /api/dashboard
                           ▼
┌──────────────────────────────────────────────────────────────┐
│                         BFF (8085)                            │
│  WebFlux · WebClient · Resilience4j · Actuator · Prometheus  │
└───────┬────────────────────────────────────┬─────────────────┘
        │                                    │
        │ Circuit breaker + Retry            │ Circuit breaker + Retry
        ▼                                    ▼
┌───────────────────┐              ┌───────────────────┐
│ mock-user-service │              │ mock-product-svc  │
│      (8082)       │              │      (8084)        │
│  GET /api/users/me│              │  GET /api/products│
└───────────────────┘              └───────────────────┘
        │                                    │
        └────────────────┬───────────────────┘
                         │ scrape /actuator/prometheus
                         ▼
                ┌─────────────────┐     ┌─────────┐
                │   Prometheus    │────▶│ Grafana │
                │     (9090)      │     │ (3000)  │
                └─────────────────┘     └─────────┘

Tech Stack

Layer Technology
Runtime Java 21
Framework Spring Boot 3.2, Spring WebFlux
Resilience Resilience4j (circuit breaker, retry)
HTTP Client WebClient (reactive)
Metrics Micrometer, Prometheus
Build Gradle (Kotlin DSL)
Containers Docker, Docker Compose

Prerequisites

  • Java 21+ (for local run and tests)
  • Docker & Docker Compose (for full stack)

Quick Start

Option 1: Run everything with Docker (recommended)

From the project root:

docker compose up -d --build

This builds and starts:

  • mock-user-service (8082)
  • mock-product-service (8084)
  • bff (8085)
  • Prometheus (9090)
  • Grafana (3000)

Then open:

In Grafana, add a Prometheus data source with URL: http://prometheus:9090.


Option 2: Run locally (without Docker)

  1. Start mock services and BFF (each in its own terminal):
./gradlew :mock-user-service:bootRun    # port 8082
./gradlew :mock-product-service:bootRun # port 8084
./gradlew :bff:bootRun                  # port 8085
  1. Call the BFF:
curl http://localhost:8085/api/dashboard
  1. (Optional) Run Prometheus and Grafana via Docker for metrics:
docker compose up -d prometheus grafana

Use prometheus.yml (target localhost:8085) when Prometheus runs on the host; use prometheus-docker.yml (target bff:8085) when everything runs in Docker.


API

GET /api/dashboard

Returns aggregated user and product data.

Response (200 OK):

{
  "user": {
    "id": 1,
    "name": "John",
    "email": "john.email@email"
  },
  "products": [
    { "id": 1, "name": "milk", "price": 20 },
    { "id": 2, "name": "bread", "price": 40 },
    { "id": 3, "name": "coke", "price": 60 }
  ]
}

If a backend is unavailable, the BFF returns the same structure with fallback values (e.g. user with null fields or products as an empty array) and still responds with 200 OK.

Actuator


Configuration

Property Description Default (BFF)
server.port BFF server port 8085
user-service.base-url User service base URL http://localhost:8082
product-service.base-url Product service base URL http://localhost:8084

Override in Docker with environment variables: USER_SERVICE_BASE_URL, PRODUCT_SERVICE_BASE_URL.

Resilience4j (circuit breaker, retry) is configured in bff/src/main/resources/application.yml under resilience4j.*.


Project Structure

resilient_bff/
├── bff/                    # BFF service (WebFlux, Resilience4j, Actuator)
│   ├── src/main/java/bff/
│   ├── src/test/java/bff/
│   └── Dockerfile
├── mock-user-service/      # Mock user API
├── mock-product-service/   # Mock products API
├── docker-compose.yml      # BFF + mocks + Prometheus + Grafana
├── prometheus.yml          # Prometheus config (host)
├── prometheus-docker.yml   # Prometheus config (Docker network)
├── build.gradle.kts
└── settings.gradle.kts

Tests

./gradlew :bff:test
  • UserServiceTest — success and fallback with mocked WebClient and StepVerifier.
  • ProductServiceTest — same for product list and empty fallback.
  • BffControllerTest@WebFluxTest with mocked services; checks 200 and JSON shape for full and fallback responses.

Observability

  • Prometheus scrapes BFF at /actuator/prometheus (job bff).
  • Grafana can use the JVM (Micrometer) or Spring Boot dashboards (e.g. import ID 4701 or 11378) with the Prometheus data source.
  • Resilience4j metrics (e.g. circuit breaker state) are exposed via the same actuator endpoint.

License

MIT

About

Reactive BFF that aggregates downstream APIs with circuit breaker, retry, fallbacks, and full observability (Prometheus + Grafana). Spring Boot 3, Java 21.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors