A Python demo app written with Flask-RESTful.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rypel 447d918753 [gunicorn, docker] rename config.py 1 month ago
docker [gunicorn, docker] rename config.py 1 month ago
flask [app, gunicorn] include local.env, override env vars 2 months ago
gunicorn [gunicorn, docker] rename config.py 1 month ago
nginx/conf.d [nginx] return 401 on missing api key, before passing to gunicorn 2 months ago
.coveragerc [coverage] use rounded percentage 2 months ago
.dockerignore [dockerignore] exclude more stuff 2 months ago
.editorconfig [makefile, editorconfig] fix final newlines 4 months ago
.env [docker, env, makefile] prefix DOCKER_ image variables 2 months ago
.gitignore [gitignore, env, config, makefile] recognize 'local.env' if present and override '.env' 2 months ago
LICENSE [license] fill in copyright 5 months ago
README.md [gunicorn, docker] rename config.py 1 month ago
TODO.md [todo] prepare 0.16.0 release 2 months ago
makefile [makefile] find requirements files programmatically 1 month ago
openapi.yaml [app, dockerfile, openapi] rename and document 'GET /health' route; add tags 3 months ago

README.md

flask-restful-demo

A Python app written in with the Flask-RESTful framework. It features a user management API with CRUDL operations and SQL persistence.

The Flask app speaks to a Postgres database and is being served by a Gunicorn server. Any HTTP traffic towards the server is proxy’d through Nginx.

The server, database and proxy services run as Docker containers, all set up via docker-compose.

This project uses GNU Make for tooling and environment variables for project-wide configuration.

Prerequisites

Install these through your system’s package manager:

  • Python 3.7+
  • virtualenv 16+
  • cURL 7+
  • GNU Make 4+
  • Docker 18.09+
  • docker-compose 1.24+
  • Firefox (or any other browser)

Docker

Add yourself to the docker group with:

sudo gpasswd -a ${USER} docker

Usage

For a quick start simply type:

make all

Source the base .env file and export needed variables into environment:

set -a; [ -f .env ] && . .env; set +a

Query the API with cURL (-i for header output):

curl -iH "$API_KEY_HEADER" localhost/users                                                         # get all users
curl -iH "$API_KEY_HEADER" localhost/users?name-starts-with=foo                                    # get users, filtered
curl -iH "$API_KEY_HEADER" -H "$JSON_HEADER" -d '{"name":"foobar"}' localhost/users                # create a user
curl -iH "$API_KEY_HEADER" localhost/users/1234                                                    # get a user
curl -iH "$API_KEY_HEADER" -X PATCH -H "$JSON_HEADER" -d '{"name":"slurm"}' localhost/users/1234   # update a user
curl -iH "$API_KEY_HEADER" -X DELETE localhost/users/1234                                          # delete a user

Access the (proxy-restricted) app health route through the server container:

make health

Stop and remove the server, database and proxy containers:

make down

Development

A toolchain is defined in the makefile, that allows executing common tooling steps. Some makefile targets respect environment variables like PROJECT_ENV and execute conditionally.

Configuration

Values that change often and/or values that are needed by multiple components should be defined as environment variables in .env. The rest should be defined in their respective config files.

Secrets

Secrets should be defined as environment variables in a non-committed local.env - to override the base .env.

Environment

The .env file contains environment variables for use by various files. To ease sourcing & exporting, you can add this function to your shell config, e.g. ~/.bashrc:

dotenv () {
  set -a
  [ -f .env ] && . .env
  [ -f local.env ] && . local.env
  set +a
}

Then, calling $ dotenv will source and export variables from .env and/or local.env files in the current working directory into the shell’s environment.

Server

The server config resides in the gunicorn/config.py file.

App

The app config resides in the flask/app/config.py file, separated into environment-specific classes.

Containers

Base config is docker-compose.yml. Additionally, .local.yml, .dev.yml or .prod.yml config files can be appended to override the base:

docker-compose -f <BASE> -f <LOCAL-OR-DEV-OR-PROD-OVERRIDE>

The makefile dynamically decides which one to append by reading the PROJECT_ENV environment variable.

Clean-up

Remove all additional state (keeps local.env):

make clean

Remove virtualenv and pip dependencies:

make clean-venv

Remove database volume (asks before actually removing):

make clean-volume

Remove app/server image:

make clean-image

Linting & Testing

Run Flake8 to lint all python modules:

make lint

Run nose2 with test coverage report:

make test

Virtualenv

Install virtualenv with Python, Pip and setuptools:

make venv

Optional: when using binaries/libs from ven directly, then source virtualenv activation script in local shell:

. venv/bin/activate

For non-bash shells see: venv/bin/activate.[csh|fish|ps1]

Dependencies

Install dependencies defined in requirements.txt and requirements.local.txt files:

make install

Interactively upgrade installed dependencies and, if successful, update all requirements files:

make upgrade

Containers

Show final container config:

make config

Pull python, database and proxy container images:

make pull

Build app/server container image:

make build
make build NO_CACHE=1  # optionally ignore build cache

Create and start all containers in background:

make up
make up BUILD=1  # optionally build image beforehand

Attach to the logs of running containers:

make logs

Stop and remove running containers:

make down

To only stop a specific service use docker-compose [-p ... -f ...] stop server instead.

Specification

Optional – to use any other browser than Firefox, set this environment variable beforehand:

export BROWSER=chrome-or-whatever

Serve a local Swagger UI instance and open it in browser (auto-loads the openapi.yaml spec):

make swagger-ui

Serve a local Swagger Editor instance and open it in browser (there, import openapi.yaml manually):

make swagger-editor

Repo layout

Files marked [*] have accompanying environment specific override files.

- docker/
  - docker-compose[*].yml   -> container setup config
  - Dockerfile              -> server container image definition
  - entrypoint.sh           -> server container runtime script
- flask/
  - app/                    
    - __init__.py           -> app package, contains create_app() factory
    - config.py             -> app config
  - tests/                  -> app unit & integration tests
  - requirements[*].txt     -> app dependency config
  - run.py                  -> server runtime script
- gunicorn/
  - gunicorn.py             -> server config
  - requirements.txt        -> server dependency config
- nginx/
  - conf.d/
    - default.conf          -> proxy config
- venv/                     -> installed dependencies
- [*].env                   -> environment variables
- makefile                  -> tool chain
- openapi.yaml              -> API specification