A comprehensive Spring Boot REST API for an Airbnb-like hotel booking platform with dynamic pricing, inventory management, and secure payment processing.
- Features
- Technology Stack
- Prerequisites
- Installation
- Configuration
- API Documentation
- API Endpoints
- Authentication
- Response Format
- Database Schema
- Dynamic Pricing
- Payment Integration
- Testing
- Deployment
- Contributing
-
User Authentication & Authorization
- JWT-based authentication with access and refresh tokens
- Role-based access control (Guest, Hotel Manager)
- OAuth2 Google login support
- Secure password encryption with BCrypt
- HttpOnly cookie-based refresh token storage
-
Hotel Management
- Complete CRUD operations for hotels
- Advanced hotel search with date and location filters
- Hotel activation/deactivation
- Hotel reports and analytics
- Photo and amenities management
-
Room Management
- Room types with detailed amenities
- Base pricing configuration
- Capacity and availability settings
- Room photo galleries
-
Inventory Management
- Date-based inventory tracking
- Real-time availability checking
- Inventory updates with surge factors
- Closed dates management
-
Booking System
- Multi-step booking flow
- Guest information management
- Booking status tracking (PENDING, CONFIRMED, CANCELLED)
- Booking cancellation with proper cleanup
-
Dynamic Pricing
- Multiple pricing strategies
- Real-time price calculation
- Date-based price queries
-
Payment Processing
- Stripe integration for secure payments
- Payment session creation
- Webhook handling for payment events
- Payment status tracking
-
API Documentation
- Swagger/OpenAPI integration
- Interactive API explorer
- Auto-generated documentation
-
Error Handling
- Global exception handling
- Standardized error responses
- Detailed error messages
-
Security
- CORS configuration
- Secure cookie settings
- JWT token validation
- Role-based endpoint protection
- Framework: Spring Boot 3.5.7
- Language: Java 17
- Build Tool: Maven
- Database: PostgreSQL
- Security: Spring Security, JWT (jjwt 0.12.6)
- Payment: Stripe Java SDK 24.1.0
- Documentation: SpringDoc OpenAPI 2.8.14
- Mapping: ModelMapper 3.2.5
- OAuth: Spring OAuth2 Client & Resource Server
Before you begin, ensure you have the following installed:
- Java Development Kit (JDK) 17 or higher
- Maven 3.6 or higher
- PostgreSQL 12 or higher
- Stripe Account (for payment processing)
- Google OAuth Credentials (optional, for OAuth login)
git clone <repository-url>
cd airbnbappCreate a PostgreSQL database:
CREATE DATABASE airbnb;Create a .env file in the root directory or set the following environment variables:
# Database Configuration
DB_URL=jdbc:postgresql://localhost:5432/airbnb
DB_USERNAME=your_database_username
DB_PASS=your_database_password
# JWT Configuration
JWT_SECRET=your_jwt_secret_key_minimum_32_characters_long
# Google OAuth (Optional)
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
# Stripe Configuration
STRIPE_SECRET=sk_test_your_stripe_secret_key
STRIPE_WEBOOK_SECRET=whsec_your_stripe_webhook_secretImportant:
- JWT secret should be at least 32 characters long
- Use test keys for development, production keys for deployment
- Webhook secret is obtained from Stripe Dashboard β Webhooks
Using Maven:
# Build the project
mvn clean install
# Run the application
mvn spring-boot:runUsing JAR:
# Build JAR
mvn clean package
# Run JAR
java -jar target/airbnbapp-0.0.1-SNAPSHOT.jarThe API will be available at: http://localhost:8081
Key configuration options in application.properties:
- Server Port:
8081(default) - Database: Auto-configured via environment variables
- JPA:
ddl-auto=update(auto-generates schema) - Swagger: Enabled by default
- CORS: Configured in
CorsConfig.java
Allowed origins are configured in WebSecurityConfig.java:
http://localhost:5173(development)https://neonstays-frontend.onrender.comhttps://neonstays.vercel.app
Once the application is running, access the interactive API documentation:
- Swagger UI: http://localhost:8081/swagger-ui.html
- OpenAPI JSON: http://localhost:8081/v3/api-docs
All endpoints are prefixed with: /api/v1
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /signup |
Register a new user | No |
| POST | /login |
User login | No |
| POST | /refresh |
Refresh access token | No (cookie) |
| POST | /logout |
User logout | No |
Signup Request:
{
"name": "John Doe",
"email": "john@example.com",
"password": "securePassword123",
"dateOfBirth": "1990-01-15",
"gender": "MALE"
}Login Request:
{
"email": "john@example.com",
"password": "securePassword123"
}Login Response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Refresh token is set as HttpOnly cookie
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | / |
Search hotels | No |
| GET | /{hotelId}/info |
Get hotel details with rooms | No |
| GET | /{roomId}/price?start={date}&end={date} |
Get dynamic room price | No |
Search Request:
{
"city": "New York",
"startDate": "2024-01-15",
"endDate": "2024-01-20",
"roomsCount": 1,
"page": 0,
"size": 20
}Search Response:
{
"content": [
{
"hotel": {
"id": 1,
"name": "Grand Hotel",
"city": "New York",
"photos": ["url1", "url2"],
"amenities": ["WiFi", "Pool", "Gym"]
},
"price": 150.00
}
],
"totalElements": 10,
"totalPages": 1,
"size": 20,
"number": 0
}| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /init |
Initialize booking | Yes |
| POST | /{bookingId}/addGuests |
Add guests to booking | Yes |
| POST | /{bookingId}/payments |
Initiate Stripe payment | Yes |
| POST | /{bookingId}/cancel |
Cancel booking | Yes |
| POST | /{bookingId}/status |
Get booking status | Yes |
Initialize Booking:
{
"hotelId": 1,
"roomId": 1,
"checkInDate": "2024-01-15",
"checkOutDate": "2024-01-20",
"roomsCount": 1
}Add Guests:
[
{
"name": "John Doe",
"gender": "MALE",
"age": 30
}
]Payment Response:
{
"sessionUrl": "https://checkout.stripe.com/pay/cs_test_..."
}| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /profile |
Get user profile | Yes |
| PATCH | /profile |
Update user profile | Yes |
| GET | /bookings |
Get user's bookings | Yes |
| PATCH | /promote-to-host |
Promote to hotel manager | Yes |
| Method | Endpoint | Description | Auth Required | Role Required |
|---|---|---|---|---|
| GET | / |
Get all hotels | Yes | HOTEL_MANAGER |
| POST | / |
Create hotel | Yes | HOTEL_MANAGER |
| GET | /{hotelId} |
Get hotel by ID | Yes | HOTEL_MANAGER |
| PUT | /{hotelId} |
Update hotel | Yes | HOTEL_MANAGER |
| DELETE | /{hotelId} |
Delete hotel | Yes | HOTEL_MANAGER |
| PATCH | /{hotelId}/activate |
Activate hotel | Yes | HOTEL_MANAGER |
| GET | /{hotelId}/bookings |
Get hotel bookings | Yes | HOTEL_MANAGER |
| GET | /{hotelId}/reports |
Get hotel reports | Yes | HOTEL_MANAGER |
Create Hotel:
{
"name": "Luxury Resort",
"city": "Miami",
"photos": ["url1", "url2"],
"amenities": ["WiFi", "Pool", "Spa"],
"hotelContactInfo": {
"phone": "+1234567890",
"email": "contact@resort.com"
},
"active": true
}| Method | Endpoint | Description | Auth Required | Role Required |
|---|---|---|---|---|
| GET | / |
Get all rooms | Yes | HOTEL_MANAGER |
| POST | / |
Create room | Yes | HOTEL_MANAGER |
| GET | /{roomId} |
Get room by ID | Yes | HOTEL_MANAGER |
| PUT | /{roomId} |
Update room | Yes | HOTEL_MANAGER |
| DELETE | /{roomId} |
Delete room | Yes | HOTEL_MANAGER |
Create Room:
{
"type": "Deluxe Suite",
"basePrice": 200.00,
"photos": ["url1", "url2"],
"amenities": ["WiFi", "TV", "Mini Bar"],
"totalCount": 10,
"capacity": 2
}| Method | Endpoint | Description | Auth Required | Role Required |
|---|---|---|---|---|
| GET | /rooms/{roomId} |
Get inventory by room | Yes | HOTEL_MANAGER |
| PATCH | /rooms/{roomId} |
Update inventory | Yes | HOTEL_MANAGER |
Update Inventory:
{
"startDate": "2024-01-15",
"endDate": "2024-01-20",
"surgeFactor": 1.5,
"closed": false
}| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /session/{sessionId} |
Get payment details | No |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /payment |
Stripe webhook handler | No (Stripe signature) |
-
Login
- Send POST request to
/api/v1/auth/loginwith credentials - Response contains
accessTokenin body refreshTokenis set as HttpOnly cookie (expires in 7 days)
- Send POST request to
-
Authenticated Requests
- Include access token in Authorization header:
Authorization: Bearer <accessToken>
- Include access token in Authorization header:
-
Token Refresh
- When access token expires (typically 15 minutes), call
/api/v1/auth/refresh - Refresh token is automatically sent via cookie
- Returns new access token
- When access token expires (typically 15 minutes), call
-
Logout
- Call
/api/v1/auth/logoutto clear refresh token cookie
- Call
- GUEST: Can search hotels, make bookings, manage profile
- HOTEL_MANAGER: All guest permissions + hotel/room/inventory management
Access tokens contain:
- User ID
- Roles
- Expiration time
All API responses follow a standardized format:
{
"timeStamp": "2024-01-15T10:30:00",
"data": {
// Response data here
},
"error": null
}{
"timeStamp": "2024-01-15T10:30:00",
"data": null,
"error": {
"status": "BAD_REQUEST",
"message": "Detailed error message",
"subErrors": []
}
}200 OK- Successful request201 CREATED- Resource created successfully204 NO_CONTENT- Successful request with no content400 BAD_REQUEST- Invalid request data401 UNAUTHORIZED- Authentication required403 FORBIDDEN- Insufficient permissions404 NOT_FOUND- Resource not found500 INTERNAL_SERVER_ERROR- Server error
- User: User accounts with authentication and role information
- Hotel: Hotel information, photos, amenities, contact details
- Room: Room types with pricing, capacity, and amenities
- Inventory: Date-based room availability and pricing
- Booking: Booking records with status and dates
- Guest: Guest information linked to bookings
- User β Bookings (One-to-Many)
- Hotel β Rooms (One-to-Many)
- Room β Inventory (One-to-Many)
- Booking β Guests (One-to-Many)
- Booking β Room (Many-to-One)
The application uses spring.jpa.hibernate.ddl-auto=update, which:
- Automatically creates/updates database schema on startup
- Preserves existing data
- Note: Use
validateornonein production
The system implements multiple pricing strategies that can be combined:
- Base Pricing: Standard room price
- Surge Pricing: Price increase during high demand periods
- Holiday Pricing: Special pricing for holidays
- Occupancy Pricing: Price adjustment based on number of guests
- Urgency Pricing: Price increase for last-minute bookings
Pricing is calculated dynamically based on:
- Base room price
- Date range
- Surge factors in inventory
- Booking urgency
- Holiday calendar
The backend integrates with Stripe for secure payment processing:
-
Payment Session Creation
- Endpoint:
POST /api/v1/bookings/{bookingId}/payments - Creates Stripe Checkout session
- Returns session URL for frontend redirect
- Endpoint:
-
Webhook Handling
- Endpoint:
POST /api/v1/webhook/payment - Handles Stripe payment events
- Updates booking status automatically
- Verifies webhook signatures
- Endpoint:
-
Payment Status
- Tracked in booking entities
- Queryable via payment session ID
- Create Stripe account
- Get API keys from Stripe Dashboard
- Set up webhook endpoint in Stripe Dashboard:
- URL:
https://your-domain.com/api/v1/webhook/payment - Events:
checkout.session.completed,payment_intent.succeeded
- URL:
- Copy webhook signing secret to environment variables
mvn test- Unit tests for services
- Integration tests for controllers
- Repository tests
-
Environment Variables
- Set all required environment variables
- Use strong JWT secret (32+ characters)
- Use production Stripe keys
- Configure production database
-
Database
- Change
ddl-autotovalidateornone - Run migrations manually if needed
- Set up database backups
- Change
-
CORS Configuration
- Update allowed origins in
WebSecurityConfig.java - Remove localhost origins in production
- Update allowed origins in
-
Security
- Enable HTTPS
- Use secure cookies (already configured)
- Review security headers
-
Build and Deploy
mvn clean package java -jar target/airbnbapp-0.0.1-SNAPSHOT.jar
FROM openjdk:17-jdk-slim
COPY target/airbnbapp-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]- Date Format: All dates must be in ISO format (YYYY-MM-DD)
- JWT Secret: Must be at least 32 characters long
- Refresh Tokens: Expire after 7 days, stored as HttpOnly cookies
- Access Tokens: Typically expire after 15 minutes (configurable)
- Database: Schema auto-updates on startup (change for production)
- CORS: Configured for specific origins (update for your frontend)
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Follow Java naming conventions
- Use Lombok for boilerplate code
- Add Javadoc comments for public methods
- Write unit tests for new features
This project is licensed under the MIT License.
Divyansh
For issues, questions, or contributions:
- Open an issue on GitHub
- Contact the maintainer
- Spring Boot team for the excellent framework
- Stripe for payment processing
- All contributors and users of this project