Skip to content

DewaldOosthuizen/python-rest-tutorial

Repository files navigation

python_rest_tutorial

CI Codacy Badge

Donate License

A comprehensive guide and implementation to help developers learn how to create RESTful APIs using Python, Flask, Docker, and MongoDB. It demonstrates best practices for building scalable and efficient APIs, leveraging Python's capabilities alongside Docker for containerization. The repository serves as an educational resource for both beginners and experienced developers looking to refine their skills in REST API development.

Reference article: https://www.dvt.co.za/news-insights/insights/item/355-restful-web-services-using-python-flask-docker-and-mongodb [Specific to commit sha 87722d939eadaca906fade165829eddb59f906d1] The project has since been updated to use JWT instead of basic auth

Repository Structure

web/                  Python application source (Flask app + Dockerfile)
web/requirements.txt  Pinned runtime and dev dependencies
web/tests/            Unit tests for the Flask application
tests/                Integration / config-level tests
scripts/lint.sh       Local lint script (mirrors CI exactly)
docker-compose.yml    Service definitions: app + MongoDB
.env.example          Environment variable template

Getting Started

1. Configure environment variables

cp .env.example .env

Edit .env and set a strong JWT_SECRET before starting the application.

2. Build and start the containers

sudo docker-compose build
sudo docker-compose up

3. Verify the service

Open http://localhost:5000/hello in your browser or run:

curl http://localhost:5000/hello

Expected response: "Hello World!"

Environment Variables

Variable Default Description
MONGO_URI mongodb://my_db:27017/ MongoDB connection string. Override for remote or authenticated instances.
JWT_SECRET (required) Secret key for signing and verifying JWT tokens. Use a long random string.

Never hardcode or commit JWT_SECRET.

Authentication

The API uses JWT (JSON Web Token) bearer authentication.

1. Register a user — POST /register

curl -X POST http://localhost:5000/register \
  -H "Content-Type: application/json" \
  -d '{"username": "alice", "password": "yourpassword"}'

2. Obtain a token — POST /login

curl -X POST http://localhost:5000/login \
  -H "Content-Type: application/json" \
  -d '{"username": "alice", "password": "yourpassword"}'

Response (200 OK):

{"status": 200, "token": "<signed-jwt>"}

On invalid credentials the endpoint returns 401.

3. Call protected endpoints — Authorization: Bearer

Pass the token in the Authorization header on every call to /retrieve and /save:

# Retrieve messages
curl -X POST http://localhost:5000/retrieve \
  -H "Authorization: Bearer <token>"

# Save a message
curl -X POST http://localhost:5000/save \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello!"}'

Missing, expired, or tampered tokens return 401 Unauthorized.

Using Postman

Add Content-Type: application/json to your request headers.

If you prefer not to set the content-type header manually, the endpoints use request.get_json(force=True) which will parse the body as JSON regardless.

See #1 for context.

Running the Tests

Install dependencies and run the full test suite from the project root:

pip install -r web/requirements.txt
pytest -v

This runs both web/tests/ (unit tests) and tests/ (config and API-contract tests).

Linting

The project uses Ruff for linting and formatting (replaces flake8 + isort + black in a single fast tool).

Run locally (mirrors CI exactly)

# Check only
./scripts/lint.sh

# Auto-fix then check
./scripts/lint.sh --fix

Run ruff directly

ruff check web/ tests/           # lint
ruff format --check web/ tests/  # format check
ruff format web/ tests/          # apply formatting

Ruff is included in web/requirements.txt so no separate install is needed once the project dependencies are installed.

CI Pipeline

Every push and pull request runs the GitHub Actions CI pipeline:

lint  →  test
  • lintruff check + ruff format --check across web/ and tests/
  • testpytest -v (only runs if lint passes)

The pipeline is defined in .github/workflows/ci.yml.

Dependencies

All runtime and development dependencies are pinned in web/requirements.txt to ensure reproducible builds across local, CI, and Docker environments.

Package Version Role
Flask 3.1.3 Web framework
Werkzeug >=3.0.0 WSGI utilities
flask-restful 0.3.10 REST resource helpers
pymongo 4.7.2 MongoDB driver
bcrypt 4.1.3 Password hashing
PyJWT >=2.8.0 JWT authentication
pytest 9.0.3 Test runner (dev)
pytest-cov >=4.1 Coverage reports (dev)
ruff >=0.5.0 Linting and formatting (dev)

Upgrade procedure

  1. Update the version in web/requirements.txt.
  2. Reinstall: pip install -r web/requirements.txt
  3. Run the test suite: pytest -v
  4. Run the linter: ./scripts/lint.sh
  5. If all checks pass, commit the updated requirements.txt.

Contributing

Contributions are welcome. Please read CONTRIBUTING.md for the full workflow, including how to pick up an issue, branch naming conventions, local validation steps, and the pull request process.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors