Skip to content

About

A simple FastAPI service for managing flight records with CRUD, filtering, sorting, and pagination.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Flight Management API

A small FastAPI service for managing flight records: create, read, update, delete, and list with filtering, sorting and pagination. Every response, including errors, uses the same JSON envelope. Built as a hiring take-home; kept deliberately small.

Stack: Python 3.9+, FastAPI, SQLAlchemy 2, Pydantic 2, SQLite (any SQLAlchemy URL works), pytest.

Run

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload

Interactive docs: http://localhost:8000/docs

The database defaults to ./flights.db and is created on first start. Point DATABASE_URL at anything SQLAlchemy understands to use another database:

DATABASE_URL=mysql+pymysql://user:pass@localhost/flights uvicorn app.main:app

Endpoints

Method Path Purpose
POST /flights/ Create a flight
GET /flights/ List flights (filter, sort, paginate)
GET /flights/{id} Get one flight
PUT /flights/{id} Partial update; only the fields sent change
DELETE /flights/{id} Delete a flight

List parameters: origin, destination, status, process_id (filters), sort_by (one of flight_number, departure_time, arrival_time, seats_available, created_at, updated_at), sort_order (asc/desc), page, page_size (max 100).

Response envelope

{ "status": "success", "message": "Flight created", "data": { "flight_id": 1, "...": "..." } }

Errors use the same shape with "status": "error". Validation errors carry the field list in data:

{ "status": "error", "message": "Validation error", "data": [ { "loc": ["body", "arrival_time"], "msg": "..." } ] }
Code When
404 Flight id does not exist
409 flight_number already exists
422 Invalid input, unknown sort field, or an update that would leave the record invalid

Validation rules

  • arrival_time must be after departure_time; duration_minutes is derived from the two.
  • seats_available cannot exceed seats_total; it defaults to seats_total on create.
  • Updates are validated against the merged record, so a partial update cannot bypass a rule that creation enforces.
  • Timezone-aware datetimes are converted to UTC and stored naive.

Example

curl -X POST http://localhost:8000/flights/ -H "Content-Type: application/json" -d '{
  "flight_number": "IR700", "origin": "IKA", "destination": "MHD",
  "departure_time": "2025-11-10T10:00:00", "arrival_time": "2025-11-10T11:30:00",
  "aircraft_type": "A320", "seats_total": 150
}'

curl "http://localhost:8000/flights/?origin=IKA&sort_by=departure_time&sort_order=desc&page=1&page_size=5"

curl -X PUT http://localhost:8000/flights/1 -H "Content-Type: application/json" -d '{"status": "delayed"}'

Layout

app/
  main.py          app factory, error handlers (envelope for all errors)
  db.py            engine, session, DATABASE_URL
  models.py        SQLAlchemy model and FlightStatus enum
  schemas.py       Pydantic request/response models and validation rules
  routers/         HTTP layer: paths, query parameters, response envelope
  services/        business rules: 404/409 mapping, merged-record validation on update
  repositories/    database access only
tests/
  test_flights.py  one test per endpoint against an in-memory SQLite database

Tests

pytest

Each test gets a fresh in-memory database, so the suite is repeatable and never touches flights.db. Warnings are treated as errors, so a deprecated API call fails the run.

Licence

MIT

About

A simple FastAPI service for managing flight records with CRUD, filtering, sorting, and pagination.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages