Skip to content

Daniel23-stack/java-restaurant-api

Repository files navigation

Restaurant Reservation System - Microservices Architecture

This project implements a restaurant reservation system using two microservices built with Spring Boot, following SOLID principles. The project uses Lombok extensively to reduce boilerplate code.

Architecture Overview

  • Table Availability Microservice (Port 8080): Manages table data and availability status using hardcoded in-memory data
  • Reservation Microservice (Port 8081): Handles customer reservations, waitlist, and preferences using PostgreSQL database
  • PostgreSQL Database: Docker containerized database for Reservation Service only

Prerequisites

  • Java 17 or higher
  • Maven 3.6+ (or use an IDE like IntelliJ IDEA/Eclipse)
  • Docker and Docker Compose
  • PostgreSQL 15 (via Docker) - only required for Reservation Service

Project Structure

restaurant/
├── table-service/          # Table Availability Microservice
│   ├── src/main/java/com/restaurant/table/
│   ├── pom.xml
│   └── lombok.config
├── reservation-service/     # Reservation Microservice
│   ├── src/main/java/com/restaurant/reservation/
│   ├── pom.xml
│   └── lombok.config
├── docker-compose.yml       # PostgreSQL container setup
├── lombok.config            # Global Lombok configuration
└── README.md

Technologies Used

  • Spring Boot 3.2.0: Framework for building microservices
  • Spring WebFlux: For reactive HTTP client (WebClient)
  • Spring Data JPA: For database operations (Reservation Service)
  • PostgreSQL 15: Database for Reservation Service
  • Lombok: Reduces boilerplate code (getters, setters, constructors, builders, logging)
  • SpringDoc OpenAPI (Swagger): API documentation
  • Docker Compose: Container orchestration

Setup Instructions

1. Start PostgreSQL Database

Start the PostgreSQL container using Docker Compose:

docker-compose up -d

This will create a PostgreSQL container running on port 5432 with:

  • Username: postgres
  • Password: postgrespassword
  • Database: reservation_db (auto-created)

Note: Table Service uses hardcoded data and does not require PostgreSQL.

Verify the container is running:

docker ps

2. Build and Run Services

Option A: Using Maven (Command Line)

Build Table Service:

cd table-service
mvn clean package -DskipTests
mvn spring-boot:run

Build Reservation Service:

cd reservation-service
mvn clean package -DskipTests
mvn spring-boot:run

Option B: Using IDE (Recommended)

  1. IntelliJ IDEA / Eclipse:

    • Open the project root folder
    • Let IDE import Maven projects
    • Run TableApplication.java (table-service)
    • Run ReservationApplication.java (reservation-service)
  2. VS Code:

    • Install Java Extension Pack
    • Open project folder
    • Run Spring Boot applications from the IDE

Option C: Run JAR Files (After Building)

# Table Service
cd table-service
java -jar target/table-service-1.0.0.jar

# Reservation Service (in another terminal)
cd reservation-service
java -jar target/reservation-service-1.0.0.jar

3. Service URLs

API Documentation (Swagger)

Once both services are running, access Swagger UI:

API Documentation (JSON):

API Endpoints

Table Availability Microservice

GET /tables/{tableId}

Get table details including availability status.

Example Request:

curl http://localhost:8080/tables/T001

Example Response:

{
  "tableId": "T001",
  "capacity": 4,
  "location": "Window",
  "available": true
}

Error Response (404):

{
  "error": "Table not found"
}

PUT /tables/{tableId}

Update table availability status.

Example Request:

curl -X PUT http://localhost:8080/tables/T001 \
  -H "Content-Type: application/json" \
  -d '{"available": false}'

Example Response:

{
  "tableId": "T001",
  "capacity": 4,
  "location": "Window",
  "available": false
}

Reservation Microservice

POST /reservations

Process a reservation request or cancellation.

Example Request - Create Reservation:

curl -X POST http://localhost:8081/reservations \
  -H "Content-Type: application/json" \
  -d '{
    "tableId": "T001",
    "customerId": "C001",
    "reservationType": "reserve",
    "preferences": ["Window", "Quiet"]
  }'

Example Response (Table Available):

{
  "reservationId": "R001",
  "status": "success",
  "tableId": "T001",
  "waitlistMessage": null
}

Example Response (Table Not Available - Waitlist):

{
  "reservationId": null,
  "status": "waitlisted",
  "tableId": "T001",
  "waitlistMessage": "You are #3 in the queue."
}

Example Request - Cancel Reservation:

curl -X POST http://localhost:8081/reservations \
  -H "Content-Type: application/json" \
  -d '{
    "tableId": "T001",
    "customerId": "C001",
    "reservationType": "cancel",
    "preferences": []
  }'

Example Response (Cancellation with Waitlist Fulfillment):

{
  "reservationId": "R002",
  "status": "success",
  "tableId": "T001",
  "waitlistMessage": null
}

Example Response (Simple Cancellation):

{
  "reservationId": "R001",
  "status": "success",
  "tableId": "T001",
  "waitlistMessage": null
}

Error Responses

404 - Table Not Found:

{
  "error": "Table not found"
}

400 - Invalid Reservation Type:

{
  "error": "Invalid reservation type"
}

500 - Reservation Processing Failed:

{
  "error": "Reservation processing failed"
}

Hardcoded Table Data

The Table Service uses the following hardcoded table data (initialized in memory):

Table ID Capacity Location Available
T001 4 Window true
T002 2 Corner false
T003 6 Center true
T004 8 Balcony false

Database Configuration

PostgreSQL Connection Details

The Reservation Service connects to PostgreSQL with the following configuration:

  • Host: localhost
  • Port: 5432
  • Database: reservation_db
  • Username: postgres
  • Password: postgrespassword
  • Driver: org.postgresql.Driver
  • Connection URL: jdbc:postgresql://localhost:5432/reservation_db

These settings can be found in reservation-service/src/main/resources/application.properties.

Database Schema

Reservation Service Database (reservation_db)

reservations table:

  • id (BIGINT, Primary Key)
  • reservation_id (VARCHAR, Unique) - Format: R001, R002, etc.
  • table_id (VARCHAR)
  • customer_id (VARCHAR)
  • status (VARCHAR) - ACTIVE, CANCELLED, FULFILLED
  • preferences (JSON) - Array of preference strings
  • created_at (TIMESTAMP)

waitlist table:

  • id (BIGINT, Primary Key)
  • customer_id (VARCHAR)
  • table_id (VARCHAR)
  • preferences (JSON) - Array of preference strings
  • position (INT) - Position in waitlist queue
  • created_at (TIMESTAMP)

Note: Table Service does not use a database. It uses in-memory hardcoded data.

Features

Reservation Flow

  1. Create Reservation (reservationType: "reserve"):

    • Customer sends POST request to /reservations with reservationType: "reserve"
    • Reservation Service checks table availability via Table Service
    • If available: Creates reservation, updates table availability, returns status: "success"
    • If not available: Adds customer to waitlist, returns status: "waitlisted" with position message
  2. Cancel Reservation (reservationType: "cancel"):

    • Customer sends POST request to /reservations with reservationType: "cancel"
    • Reservation Service cancels the reservation
    • If waitlist exists: Finds best match based on preferences and fulfills reservation
    • If no waitlist: Updates table availability to available

Waitlist Management

  • Customers are added to waitlist when tables are unavailable
  • Waitlist maintains position order (1, 2, 3, etc.)
  • When a table becomes available, the system:
    • Matches customer preferences using strategy pattern
    • Considers position (earlier = higher priority)
    • Automatically fulfills the best match
    • Updates positions of remaining waitlist entries

Preference Matching

The system uses a strategy pattern for preference matching:

  • Customers can specify preferences (e.g., "Window", "Quiet", "Corner")
  • When a table becomes available, the system finds the best match
  • Matching algorithm considers:
    • Number of matching preferences
    • Waitlist position (first-come-first-served bias)

Lombok Usage

This project uses Lombok extensively to reduce boilerplate code:

Annotations Used

  • @Data: Generates getters, setters, toString, equals, hashCode (Entities & DTOs)
  • @Builder: Enables fluent builder pattern for object creation
  • @NoArgsConstructor & @AllArgsConstructor: Constructor generation
  • @RequiredArgsConstructor: Generates constructor for final fields (dependency injection)
  • @Slf4j: Provides log field for logging (no need for Logger declaration)

Example

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TableDTO {
    private String tableId;
    private Integer capacity;
    private String location;
    private Boolean available;
}

// Usage
TableDTO table = TableDTO.builder()
    .tableId("T001")
    .capacity(4)
    .location("Window")
    .available(true)
    .build();

SOLID Principles Applied

  • Single Responsibility: Each service/class has a single, well-defined responsibility

    • TableService: Manages table data
    • ReservationService: Manages reservations
    • WaitlistService: Manages waitlist operations
    • PreferenceMatcher: Handles preference matching logic
  • Open/Closed: Preference matching uses strategy pattern (open for extension, closed for modification)

    • PreferenceMatcher interface allows different matching algorithms
  • Liskov Substitution: Interfaces for service clients ensure substitutability

    • TableServiceClient interface with TableServiceClientImpl implementation
  • Interface Segregation: Separate interfaces for different responsibilities

    • Separate interfaces for different service operations
  • Dependency Inversion: Services depend on abstractions (interfaces) rather than concrete implementations

    • Services depend on TableServiceClient interface, not implementation

Error Handling

Both services include comprehensive error handling:

  • TableNotFoundException (404): When table is not found

    • Response: {"error": "Table not found"}
  • TableServiceException (503): When Table Service is unavailable

    • Response: {"error": "Reservation processing failed"}
  • IllegalArgumentException (400): Invalid reservation type or request

    • Response: {"error": "Invalid reservation type"}
  • Validation Errors (400): Request validation errors

    • Response: {"error": "Validation message"}
  • Generic Exceptions (500): Internal server errors

    • Response: {"error": "Reservation processing failed"}

Testing the Services

PowerShell Examples

Test Table Service:

# Get table details
Invoke-RestMethod -Uri "http://localhost:8080/tables/T001" -Method GET | ConvertTo-Json

# Update table availability
$body = @{ available = $false } | ConvertTo-Json
Invoke-RestMethod -Uri "http://localhost:8080/tables/T001" -Method PUT -Body $body -ContentType "application/json" | ConvertTo-Json

Test Reservation Service:

# Create reservation
$body = @{
    tableId = "T001"
    customerId = "C001"
    reservationType = "reserve"
    preferences = @("Window", "Quiet")
} | ConvertTo-Json

Invoke-RestMethod -Uri "http://localhost:8081/reservations" -Method POST -Body $body -ContentType "application/json" | ConvertTo-Json

# Cancel reservation
$body = @{
    tableId = "T001"
    customerId = "C001"
    reservationType = "cancel"
    preferences = @()
} | ConvertTo-Json

Invoke-RestMethod -Uri "http://localhost:8081/reservations" -Method POST -Body $body -ContentType "application/json" | ConvertTo-Json

Service Status Check

Use the provided PowerShell script to check service status:

.\check-services.ps1

Stopping Services

  1. Stop the Spring Boot applications (Ctrl+C in terminal or stop in IDE)
  2. Stop PostgreSQL container:
docker-compose down

To remove volumes (deletes data):

docker-compose down -v

Troubleshooting

Maven Not Found

If Maven is not installed or not in PATH:

  • Option 1: Install Maven and add to PATH
  • Option 2: Use an IDE (IntelliJ IDEA, Eclipse) which includes Maven support
  • Option 3: Use Maven Wrapper (can be added to project)

Port Already in Use

If ports 8080 or 8081 are already in use:

  1. Find process using the port:
    Get-NetTCPConnection -LocalPort 8080,8081
  2. Update server.port in application.properties files
  3. Update table.service.url in Reservation Service if Table Service port changes

Database Connection Issues

  1. Verify PostgreSQL container is running: docker ps
  2. Check PostgreSQL logs: docker logs restaurant-postgres
  3. Verify credentials in application.properties match docker-compose.yml
  4. Ensure PostgreSQL is healthy: docker ps --filter "name=restaurant-postgres"
  5. Test PostgreSQL connection:
    docker exec -it restaurant-postgres psql -U postgres -d reservation_db

Service Communication Issues

  1. Ensure Table Service is running before Reservation Service
  2. Verify table.service.url in Reservation Service properties (default: http://localhost:8080)
  3. Check network connectivity between services
  4. Test Table Service directly: curl http://localhost:8080/tables/T001

Table Service Not Starting

Table Service does not require PostgreSQL. If it fails to start:

  • Check for port conflicts
  • Verify Java 17+ is installed: java -version
  • Check application logs for errors

Reservation Service Not Starting

  1. Ensure PostgreSQL container is running: docker ps
  2. Verify database connection in application.properties
  3. Check if database exists: PostgreSQL will auto-create if configured correctly
  4. Test PostgreSQL connection:
    docker exec -it restaurant-postgres psql -U postgres -c "\l"

Project Structure Details

Table Service

  • Uses hardcoded in-memory data (no database required)
  • Data persists only during application runtime
  • Tables are initialized on service startup

Reservation Service

  • Uses PostgreSQL database for persistence
  • Requires PostgreSQL container to be running
  • Tables are auto-created by JPA/Hibernate

Future Enhancements

  • Add authentication and authorization (JWT)
  • Implement distributed tracing (Zipkin, Jaeger)
  • Add caching layer (Redis)
  • Implement event-driven architecture with message queues (RabbitMQ, Kafka)
  • Add comprehensive unit and integration tests
  • Implement circuit breaker pattern for service resilience (Resilience4j)
  • Add Maven Wrapper for easier setup
  • Implement rate limiting
  • Add monitoring and metrics (Prometheus, Grafana)

License

This project is for educational/demonstration purposes.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published