Repository name:
python-booking
Project name: StayHub API — a property rental and booking backend inspired by platforms like Airbnb.
StayHub is a REST API backend for a property rental and booking website. Guests can search listings, save favorites, book stays, and leave reviews. Hosts can publish properties and manage booking requests. Admins can inspect users, bookings, and platform statistics.
The codebase is intentionally small and readable: FastAPI routers handle HTTP, Pydantic schemas validate input/output, SQLAlchemy models define persistence, and service functions hold booking and auth business logic.
| Name | Where it appears | Purpose |
|---|---|---|
python-booking |
GitHub repository | Generic, searchable repo name for portfolio and job applications |
| StayHub API | Documentation, Swagger UI, project branding | Describes what the system actually does |
The internal code still uses stayfinder in a few places (database filename, logger name) from an earlier working title. Functionality is unchanged — only the public project name was refined for clarity.
This project follows a thin router, fat service pattern common in production FastAPI apps.
HTTP Request
│
▼
Router (app/routers/) ← routing, auth dependencies, status codes
│
▼
Service (app/services/) ← business rules, validation, pricing, overlap checks
│
▼
Model (app/models/) ← SQLAlchemy ORM entities and relationships
│
▼
Database (SQLite / PostgreSQL)
| Layer | Role | Example |
|---|---|---|
| Routers | Map URLs to handlers; never embed complex logic | POST /bookings calls booking_service.create_booking() |
| Schemas | Request/response contracts with Pydantic | BookingCreate, PropertyRead, pagination wrappers |
| Services | Domain rules isolated from HTTP | Date overlap detection, nightly price calculation, role checks |
| Models | Database tables and relationships | User, Property, Booking, Review, Favorite |
| Dependencies | Reusable auth (get_current_user, require_host, require_admin) |
JWT Bearer token → current user |
| Exceptions | Typed errors → consistent JSON responses | ConflictError → HTTP 409 |
- Half-open date ranges — stays use
[check_in, check_out), so checkout day does not block the next guest's check-in. - Server-side pricing — clients send dates and guest count; the API computes
nights × price_per_night. - Role-based access — three roles (
guest,host,admin) enforced via FastAPI dependencies, not scatteredifchecks in routers. - Active booking lock — only
pendingandconfirmedbookings block availability; cancelled and completed stays free the calendar. - Database portability — SQLite for local dev and tests; PostgreSQL supported via
DATABASE_URLfor production-style setups.
python-booking/
├── app/
│ ├── main.py # FastAPI app, CORS, global exception handlers
│ ├── config.py # Settings from .env (Pydantic Settings)
│ ├── database.py # SQLAlchemy engine and session
│ ├── dependencies.py # JWT auth and role guards
│ ├── exceptions.py # AppError hierarchy → HTTP status codes
│ ├── models/ # SQLAlchemy ORM models
│ ├── schemas/ # Pydantic request/response models
│ ├── routers/ # API route modules by domain
│ └── services/ # Business logic (auth, booking, property)
├── tests/ # Pytest suite (in-memory SQLite)
├── alembic/ # Database migrations
├── seed.py # Sample users, properties, bookings, reviews
├── requirements.txt
├── .env.example
└── README.md
- JWT authentication with bcrypt password hashing
- Role-based access for guests, hosts, and admins
- Property search with filters, sorting, and pagination
- Favorite listings
- Availability checks with date-overlap detection
- Booking creation, cancellation, and host confirmation workflow
- Automatic nightly price calculation
- Reviews after completed stays (one review per guest per property)
- Admin user list, booking list, and dashboard statistics
- Alembic migrations and a sample data seed script
- Python 3.11+
- FastAPI
- SQLAlchemy 2.x
- PostgreSQL (SQLite supported locally)
- Pydantic v2
- JWT (python-jose)
- Pytest
- Alembic
- Uvicorn
- Passlib / bcrypt
Requires Python 3.11 or newer.
git clone https://github.com/web-master00/python-booking.git
cd python-bookingLinux / macOS:
python -m venv venv
source venv/bin/activateWindows:
python -m venv venv
venv\Scripts\activatepip install -r requirements.txtcp .env.example .envThe default .env uses SQLite:
DATABASE_URL=sqlite:///./stayfinder.db
SECRET_KEY=change_this_secret_key_to_a_long_random_value
ACCESS_TOKEN_EXPIRE_MINUTES=60
To use PostgreSQL, set DATABASE_URL to a connection string such as:
DATABASE_URL=postgresql+psycopg2://postgres:postgres@localhost:5432/stayfinder
Change SECRET_KEY before deploying.
alembic upgrade headpython seed.pyThis creates an admin, two hosts, several guests, 10 properties, bookings, and reviews.
All seeded accounts use the password Password123!.
| Role | |
|---|---|
admin@stayfinder.com |
admin |
maria.host@stayfinder.com |
host |
james.host@stayfinder.com |
host |
emma.guest@stayfinder.com |
guest |
liam.guest@stayfinder.com |
guest |
sophia.guest@stayfinder.com |
guest |
noah.guest@stayfinder.com |
guest |
uvicorn app.main:app --reloadSwagger UI:
http://127.0.0.1:8000/docs
ReDoc:
http://127.0.0.1:8000/redoc
Use the Authorize button in Swagger and paste a Bearer token returned by POST /auth/login.
pytestTests use an in-memory SQLite database and cover registration, login, property permissions, booking validation, and date conflicts.
| Method | Endpoint | Description |
|---|---|---|
POST |
/auth/register |
Register a guest or host |
POST |
/auth/login |
Log in and receive a JWT |
GET |
/auth/me |
Return the authenticated user |
| Method | Endpoint | Description |
|---|---|---|
GET |
/users/me |
Get the current profile |
PUT |
/users/me |
Update name or email |
| Method | Endpoint | Description |
|---|---|---|
GET |
/properties |
Search, filter, sort, and paginate listings |
GET |
/properties/{property_id} |
Property details, host info, and ratings |
POST |
/properties |
Create a listing (host or admin) |
PUT |
/properties/{property_id} |
Update a listing (owner or admin) |
DELETE |
/properties/{property_id} |
Delete a listing (owner or admin) |
GET |
/properties/{property_id}/availability |
Check date availability |
Query parameters for GET /properties include search, city, country, property_type, min_price, max_price, guests, min_bedrooms, sort (price_low, price_high, newest), page, and page_size.
| Method | Endpoint | Description |
|---|---|---|
GET |
/favorites |
List saved properties |
POST |
/favorites/{property_id} |
Add a favorite |
DELETE |
/favorites/{property_id} |
Remove a favorite |
| Method | Endpoint | Description |
|---|---|---|
POST |
/bookings |
Create a booking |
GET |
/bookings/me |
List the current user's bookings |
GET |
/bookings/{booking_id} |
Booking details |
PUT |
/bookings/{booking_id}/cancel |
Cancel a booking as the guest |
| Method | Endpoint | Description |
|---|---|---|
GET |
/properties/{property_id}/reviews |
List reviews for a property |
POST |
/properties/{property_id}/reviews |
Create a review after a completed stay |
PUT |
/reviews/{review_id} |
Update a review (owner) |
DELETE |
/reviews/{review_id} |
Delete a review (owner or admin) |
| Method | Endpoint | Description |
|---|---|---|
GET |
/host/bookings |
Bookings for the host's properties |
PUT |
/host/bookings/{booking_id}/confirm |
Confirm a pending request |
PUT |
/host/bookings/{booking_id}/cancel |
Reject or cancel a request |
PUT |
/host/bookings/{booking_id}/complete |
Mark a confirmed stay as completed |
| Method | Endpoint | Description |
|---|---|---|
GET |
/admin/users |
Paginated user list |
GET |
/admin/bookings |
All bookings, with optional status filter |
GET |
/admin/statistics |
Platform totals |
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Liveness check |
- Check-in must be before check-out and cannot be in the past.
- Guest count must be at least 1 and cannot exceed the listing's
max_guests. - Total price is
number_of_nights × price_per_night. Clients do not send a price. - Pending and confirmed bookings block overlapping dates.
- Cancelled and completed bookings do not block availability.
- Date ranges are half-open: a stay ending on the 15th does not block a new stay starting on the 15th.
| Role | Capabilities |
|---|---|
guest |
Search, favorite, book, cancel own bookings, review completed stays |
host |
Everything a guest can do, plus create and manage listings and booking requests |
admin |
Platform-wide user, booking, and statistics access |
Admin accounts cannot be created through public registration. Use the seed script or insert one directly in the database.
The API returns JSON {"detail": "..."} with these status codes:
| Code | Meaning |
|---|---|
| 400 | Invalid request (for example past dates or too many guests) |
| 401 | Missing or invalid token |
| 403 | Authenticated but not allowed |
| 404 | Resource not found |
| 409 | Conflict (duplicate email, overlapping booking, duplicate favorite) |
| 422 | Validation error |
| 500 | Unexpected server error |
Built and maintained by codemaster — @web-master00
This project is provided as a demonstration example for portfolio and learning purposes.