REST API for movie ticket reservation, built with Django REST Framework, PostgreSQL, Redis, and Docker.
- API Development
- JWT Authentication
- Database (PostgreSQL)
- Caching & Redis Lock
- Pagination
- 34 total tests (Unit/Integration)
- API Documentation
- Docker & Compose
- Git
- Advanced Security Features (Rate Limiting, Input Validation, SQL Injection Prevention, CSRF Protection)
- Asynchronous Tasks (Celery for auto-releasing expired seat locks)
- CI/CD (GitHub Actions for automated testing)
- Start the full stack:
docker compose up --buildThis starts:
app: Django APIworker: Celery worker for asynchronous tasksbeat: Celery Beat scheduler for periodic tasksdb: PostgreSQLredis: Redis
If you want to start the runtime services explicitly:
docker compose up --build app worker beat-
The API will be available at
http://localhost:8000. -
Swagger documentation will be available at
http://localhost:8000/api/docs/.
By default, the application container runs:
python manage.py migratepython manage.py seed_demo_datapython manage.py runserver 0.0.0.0:8000
The Celery services run:
worker:celery -A config worker --loglevel=infobeat:celery -A config beat --loglevel=info
If you want to disable automatic demo seeding, set SEED_DEMO_DATA=False in .env.
- Username:
demo - Password:
DemoPass123!
curl -X POST http://localhost:8000/api/auth/login/ \
-H "Content-Type: application/json" \
-d '{
"username": "demo",
"password": "DemoPass123!"
}'Store the returned access token and use it in the header:
Authorization: Bearer <ACCESS_TOKEN>
curl http://localhost:8000/api/movies/Replace <MOVIE_ID> with an id returned in the previous step.
curl http://localhost:8000/api/movies/<MOVIE_ID>/sessions/Replace <SESSION_ID> with an id returned in the previous step.
curl http://localhost:8000/api/sessions/<SESSION_ID>/seats/Replace <ACCESS_TOKEN>, <SESSION_ID>, and the seat ids.
curl -X POST http://localhost:8000/api/sessions/<SESSION_ID>/reservations/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-d '{
"seat_ids": [2, 3]
}'Use the same seat_ids reserved in the previous step.
curl -X POST http://localhost:8000/api/sessions/<SESSION_ID>/checkout/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-d '{
"seat_ids": [2, 3]
}'The response includes the generated digital tickets.
Active tickets:
curl http://localhost:8000/api/my-tickets/active/ \
-H "Authorization: Bearer <ACCESS_TOKEN>"Full purchase history:
curl http://localhost:8000/api/my-tickets/history/ \
-H "Authorization: Bearer <ACCESS_TOKEN>"You can run the demo seed manually at any time:
docker compose run --rm app sh -c "python manage.py migrate && python manage.py seed_demo_data"The command is idempotent. It creates:
- 3 movies
- 6 sessions
- 240 seats
- 1 initial ticket for the
demouser
docker compose run --rm app pytest