Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ”„ Backend for Frontend (BFF)

Orchestration layer that aggregates and enriches data from multiple microservices for the frontend.

Overview

The Backend-for-Frontend (BFF) is the orchestration layer between the frontend (Vue.js SPA) and the downstream microservices. It serves three key purposes:

  1. Data Aggregation β€” Merges data from Hotel, Room, and Booking services into composite responses (e.g., hotel details + room list, reservation + hotel + room info)
  2. Service Bridging β€” Validates cross-service constraints before forwarding (e.g., verifies hotel exists before creating a room in it)
  3. Business Enrichment β€” Calculates derived fields like total_price = room.price Γ— nights and injects user_id from JWT claims

Tech Stack

Layer Technology
Language Go 1.25
Router go-chi/chi v5
Auth JWT verification (RSA-256 public key)
HTTP Clients Custom typed clients for each downstream service
Container Docker (multi-stage Alpine build)

Architecture

app/
β”œβ”€β”€ cmd/api/          # Application entrypoint
β”‚   └── main.go
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ client/       # HTTP clients for downstream services
β”‚   β”‚   β”œβ”€β”€ client.go           # Base HTTP client
β”‚   β”‚   β”œβ”€β”€ errors.go           # Client error types
β”‚   β”‚   β”œβ”€β”€ hotel_client.go     # Hotel Service client
β”‚   β”‚   β”œβ”€β”€ room_client.go      # Room Service client
β”‚   β”‚   β”œβ”€β”€ reservation_client.go  # Legacy reservation client
β”‚   β”‚   β”œβ”€β”€ booking_client.go   # Booking Service client
β”‚   β”‚   └── payment_client.go   # Payment Service client
β”‚   β”œβ”€β”€ config/       # YAML config loader with env var expansion
β”‚   β”œβ”€β”€ handler/      # HTTP handlers, routing, JWT middleware
β”‚   β”‚   β”œβ”€β”€ handlers.go            # Base handler + health checks
β”‚   β”‚   β”œβ”€β”€ hotel_handlers.go      # Hotel aggregation endpoints
β”‚   β”‚   β”œβ”€β”€ room_handlers.go       # Room bridge endpoints
β”‚   β”‚   β”œβ”€β”€ reservation_handlers.go # Reservation orchestration
β”‚   β”‚   β”œβ”€β”€ middleware.go          # JWT, CORS, security, rate limit
β”‚   β”‚   └── routing.go            # Route definitions
β”‚   β”œβ”€β”€ helper/       # Response helpers
β”‚   β”œβ”€β”€ logging/      # Structured slog logger
β”‚   β”œβ”€β”€ models/       # Aggregated domain models
β”‚   β”‚   └── models.go             # Hotel, Room, Booking, composite types
β”‚   └── service/      # Business logic layer
β”‚       β”œβ”€β”€ service.go            # Service interface + mappings
β”‚       β”œβ”€β”€ hotel_service.go      # Hotel operations
β”‚       β”œβ”€β”€ room_service.go       # Room operations
β”‚       └── reservation_service.go # Reservation orchestration
β”œβ”€β”€ config.yaml
β”œβ”€β”€ Dockerfile
└── go.mod

API Endpoints

All endpoints require JWT authentication (except health checks).

Public Routes

Method Path Description
GET /health Liveness probe
GET /ready Readiness probe (checks downstream services)

Hotel Aggregation Endpoints

Method Path Type Description
GET /hotels Passthrough List hotels (forwarded to Hotel Service)
GET /hotels/{hotelId} Passthrough Get hotel details
GET /hotels/{hotelId}/details Aggregation Hotel + all its rooms (merged)

Room Bridge Endpoints

Method Path Type Description
GET /rooms/{roomId} Passthrough Get room details
POST /hotels/{hotelId}/rooms Bridge Verify hotel exists β†’ create room

Reservation Orchestration Endpoints

Method Path Type Description
GET /reservations Passthrough List user's reservations
GET /reservations/{id} Passthrough Get reservation
GET /reservations/{id}/details Aggregation Reservation + hotel + room (merged)
POST /reservations Orchestration Full booking flow (validate β†’ price β†’ pay β†’ book)

Flow Diagram

flowchart TD
    A["Frontend Request"] --> B["JWT Middleware"]
    B --> B1{"Token Valid?"}
    B1 -->|No| B2["401 Unauthorized"]
    B1 -->|Yes| C{"Endpoint Type?"}
    
    C -->|GET /hotels/id/details| D["AGGREGATION"]
    D --> D1["Fetch Hotel from Hotel Service"]
    D1 --> D2["Fetch Rooms from Room Service"]
    D2 --> D3["Map + Merge into HotelWithRooms"]
    D3 --> D4["Return composite JSON"]
    
    C -->|POST /hotels/id/rooms| E["BRIDGE"]
    E --> E1["Fetch Hotel from Hotel Service"]
    E1 --> E2{"Hotel Exists?"}
    E2 -->|No| E3["404 Not Found"]
    E2 -->|Yes| E4["Forward CreateRoom to Room Service"]
    E4 --> E5["Return created Room"]
    
    C -->|POST /reservations| F["ORCHESTRATION"]
    F --> F1["Extract user_id from JWT"]
    F1 --> F2["Fetch Room from Room Service"]
    F2 --> F3{"Room Exists?"}
    F3 -->|No| F4["404 Not Found"]
    F3 -->|Yes| F5["Calculate: nights Γ— room.price"]
    F5 --> F6["Process Payment via Payment Service"]
    F6 --> F7{"Payment Succeeded?"}
    F7 -->|No| F8["Return payment error"]
    F7 -->|Yes| F9["Create Booking via Booking Service"]
    F9 --> F10["Confirm Booking"]
    F10 --> F11["Return Booking JSON"]
    
    C -->|GET /reservations/id/details| G["AGGREGATION"]
    G --> G1["Fetch Booking"]
    G1 --> G2["Fetch Hotel"]
    G2 --> G3["Fetch Room"]
    G3 --> G4["Merge into BookingDetails"]
    G4 --> G5["Return composite JSON"]
    
    C -->|Passthrough| H["Forward to downstream service"]
    H --> H1["Return downstream response"]
Loading

Use Case Diagram

graph LR
    subgraph Actors
        User["πŸ‘€ Authenticated User"]
        Admin["πŸ”‘ Admin"]
        Frontend["πŸ–₯️ Vue.js Frontend"]
    end
    
    subgraph "BFF Service"
        UC1["View Hotel with Rooms"]
        UC2["Create Room (bridged)"]
        UC3["Create Reservation (orchestrated)"]
        UC4["View Reservation Details"]
        UC5["List User Reservations"]
        UC6["Browse Hotels"]
    end
    
    subgraph "Downstream Services"
        Hotel["🏨 Hotel Service"]
        Room["πŸ›οΈ Room Service"]
        Booking["πŸ“… Booking Service"]
        Payment["πŸ’³ Payment Service"]
    end
    
    Frontend --> UC1
    Frontend --> UC3
    Frontend --> UC4
    Frontend --> UC5
    Frontend --> UC6
    Admin --> UC2
    
    UC1 --> Hotel
    UC1 --> Room
    UC2 --> Hotel
    UC2 --> Room
    UC3 --> Room
    UC3 --> Payment
    UC3 --> Booking
    UC4 --> Booking
    UC4 --> Hotel
    UC4 --> Room
Loading

State Diagram

stateDiagram-v2
    [*] --> Initializing
    Initializing --> Ready : All clients created
    Ready --> Processing : Request received
    Processing --> Ready : Response sent
    Ready --> Degraded : Downstream health check fails
    Degraded --> Ready : Downstream recovers
    Ready --> ShuttingDown : SIGTERM/SIGINT
    Degraded --> ShuttingDown : SIGTERM/SIGINT
    ShuttingDown --> [*] : Graceful shutdown (30s)
    
    state Processing {
        [*] --> Authenticating
        Authenticating --> Routing
        Routing --> Aggregating : Composite endpoint
        Routing --> Bridging : Bridge endpoint
        Routing --> Orchestrating : Orchestration endpoint
        Routing --> Forwarding : Passthrough endpoint
        Aggregating --> [*]
        Bridging --> [*]
        Orchestrating --> [*]
        Forwarding --> [*]
    }
Loading

Package Diagram

graph TB
    subgraph "cmd/api"
        Main["main.go"]
    end
    
    subgraph "internal"
        subgraph "handler"
            BaseHandler["handlers.go"]
            HotelH["hotel_handlers.go"]
            RoomH["room_handlers.go"]
            ResH["reservation_handlers.go"]
            MW["middleware.go (JWT, CORS, etc.)"]
            Routes["routing.go"]
        end
        
        subgraph "service"
            SvcIF["service.go (interface + mappings)"]
            HotelSvc["hotel_service.go"]
            RoomSvc["room_service.go"]
            ResSvc["reservation_service.go"]
        end
        
        subgraph "client"
            BaseClient["client.go"]
            HotelClient["hotel_client.go"]
            RoomClient["room_client.go"]
            BookingClient["booking_client.go"]
            ResClient["reservation_client.go"]
            PayClient["payment_client.go"]
            Errors["errors.go"]
        end
        
        subgraph "models"
            Models["models.go"]
        end
        
        subgraph "config"
            Config["config.go"]
        end
    end
    
    Main --> Config
    Main --> Routes
    Main --> SvcIF
    Main --> HotelClient
    Main --> RoomClient
    Main --> BookingClient
    Main --> PayClient
    
    Routes --> BaseHandler
    Routes --> HotelH
    Routes --> RoomH
    Routes --> ResH
    Routes --> MW
    
    HotelH --> SvcIF
    RoomH --> SvcIF
    ResH --> SvcIF
    
    SvcIF --> HotelSvc
    SvcIF --> RoomSvc
    SvcIF --> ResSvc
    
    HotelSvc --> HotelClient
    HotelSvc --> RoomClient
    RoomSvc --> HotelClient
    RoomSvc --> RoomClient
    ResSvc --> BookingClient
    ResSvc --> HotelClient
    ResSvc --> RoomClient
    ResSvc --> PayClient
    
    HotelClient --> BaseClient
    RoomClient --> BaseClient
    BookingClient --> BaseClient
    PayClient --> BaseClient
Loading

Reservation Orchestration (Detailed)

The POST /reservations endpoint is the most complex flow:

1. Extract user_id from JWT claims
2. Validate CreateBookingRequest
3. Fetch Room from Room Service β†’ get price_per_night
4. Parse start_date, end_date
5. Calculate: nights = (end_date - start_date).days
6. Calculate: total_price = nights Γ— price_per_night
7. Process payment via Payment Service
   - Send: booking_id (pre-generated), amount, payment_method_id
   - On failure β†’ return error (no booking created)
8. Create Booking via Booking Service
   - Send: user_id, hotel_id, room_id, dates, total_price, guest info
9. Confirm Booking via Booking Service
   - PATCH status β†’ "confirmed"
10. Return confirmed Booking to frontend

Configuration

server:
  port: 8080

downstream_services:
  hotel_service_url: "${HOTEL_SERVICE_URL}"
  room_service_url: "${ROOM_SERVICE_URL}"
  booking_service_url: "${BOOKING_SERVICE_URL}"
  reservation_service_url: "${RESERVATION_SERVICE_URL}"
  payment_service_url: "${PAYMENT_SERVICE_URL}"
  timeout: 30s

rate_limit:
  enabled: true
  requests_per_second: 100
  burst: 200

Environment Variables

Variable Description
HOTEL_SERVICE_URL Hotel Service URL (e.g., http://hotel-service:8080)
ROOM_SERVICE_URL Room Service URL
BOOKING_SERVICE_URL Booking Service URL
RESERVATION_SERVICE_URL Reservation Service URL (same as booking)
PAYMENT_SERVICE_URL Payment Service URL

Volume Mounts (Docker)

Host Path Container Path Description
./keys/public.pem /app/keys/public.pem JWT verification key

Port Mapping

Context Port
Internal (container) 8080
External (host) 8087

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages