A REST API for a ticket reservation system built with Java 17 and Spring Boot 3.2.
- Java 17 or higher
- Gradle 8.5 or higher (not required if using Gradle Wrapper)
- Docker & Docker Compose (for DevContainer development)
The recommended way to develop is using VS Code DevContainers with Docker Compose. This provides:
- PostgreSQL 15 database
- Redis 7 for caching
- Pre-configured Java development environment
- Open the project in VS Code
- Click "Reopen in Container" when prompted (or use Command Palette: "Dev Containers: Reopen in Container")
- Run the application:
./gradlew bootRun
The docker profile is automatically activated in DevContainer.
For local testing without Docker:
./gradlew bootRun --args='--spring.profiles.active=test'The application will start at http://localhost:8080.
H2 Database Console: http://localhost:8080/h2-console
- JDBC URL:
jdbc:h2:mem:ticketdb - Username:
sa - Password: (leave empty)
| Profile | Database | Cache | Usage |
|---|---|---|---|
docker |
PostgreSQL | Redis | DevContainer development (default) |
test |
H2 | None | Local testing without Docker |
ci |
H2 | None | GitHub Actions CI/CD |
When using DevContainer, the following services are started:
| Service | Image | Port | Description |
|---|---|---|---|
app |
Custom | - | Java development container |
postgres |
postgres:15 | 5432 | PostgreSQL database |
redis |
redis:7 | 6379 | Redis cache |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/events |
Get all events |
| GET | /api/events/{id} |
Get event by ID |
| GET | /api/events/available |
Get available events |
| GET | /api/events/search?name={name} |
Search events by name |
| POST | /api/events |
Create event |
| PUT | /api/events/{id} |
Update event |
| DELETE | /api/events/{id} |
Delete event |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/tickets |
Get all tickets |
| GET | /api/tickets/{id} |
Get ticket by ID |
| GET | /api/tickets/code/{code} |
Search by ticket code |
| GET | /api/tickets/email/{email} |
Search by email address |
| GET | /api/events/{eventId}/tickets |
Get tickets for an event |
| POST | /api/events/{eventId}/tickets |
Create ticket (with pessimistic locking) |
| PATCH | /api/tickets/{id}/cancel |
Cancel ticket |
curl -X POST http://localhost:8080/api/events \
-H "Content-Type: application/json" \
-d '{
"name": "Summer Concert 2024",
"description": "Outdoor summer concert",
"venue": "Tokyo Dome",
"eventDate": "2024-08-15T18:00:00",
"totalSeats": 500,
"price": 8000
}'curl http://localhost:8080/api/eventscurl -X POST http://localhost:8080/api/events/1/tickets \
-H "Content-Type: application/json" \
-d '{
"customerName": "John Doe",
"customerEmail": "[email protected]",
"numberOfSeats": 2
}'This endpoint uses pessimistic locking to prevent overbooking when multiple concurrent requests are made.
curl http://localhost:8080/api/tickets/code/TKT-XXXXXXXXcurl -X PATCH http://localhost:8080/api/tickets/1/cancelIn the docker profile, Redis caching is enabled for improved performance:
- Events: Cached on read, invalidated on create/update/delete
- Tickets: Not cached (ticket creation/cancellation invalidates related event cache)
Cache is disabled in test and ci profiles for simpler testing.
Health check endpoint provided by Spring Boot Actuator:
curl http://localhost:8080/actuator/health./gradlew buildThe executable JAR file will be generated at build/libs/ticket-reservation-api-0.0.1-SNAPSHOT.jar.
java -jar build/libs/ticket-reservation-api-0.0.1-SNAPSHOT.jar./gradlew testJMeter is used to verify that pessimistic locking prevents overbooking under concurrent load.
- JMeter 5.6.3 or higher
-
Start the application with
testorciprofile (uses H2 database):./gradlew bootRun --args='--spring.profiles.active=test' -
Run JMeter test (in another terminal):
jmeter -n -t jmeter/ticket_booking_load_test.jmx -l results.jtl
The test creates an event with 10 seats and sends 20 concurrent booking requests. With pessimistic locking, exactly 10 bookings succeed and 10 fail with "No seats available".
Note: CI/CD uses the ci profile which automatically disables Redis caching.
# Check format
./gradlew spotlessCheck
# Apply format
./gradlew spotlessApply./gradlew checkstyleMain checkstyleTestGitHub Actions workflow runs on push/PR to main:
- lint: Code format check (Spotless) and static analysis (Checkstyle)
- test: Unit and integration tests
- build: Build application JAR
- load-test: JMeter load test to verify no overbooking