-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First commit containing the base template for a Flask API (#8)
First commit containing the base template for a Flask API
- Loading branch information
Showing
88 changed files
with
6,455 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
## Ticket | ||
|
||
{TICKET_LINK} | ||
|
||
## Changes | ||
> What was added, updated, or removed in this PR. | ||
## Context for reviewers | ||
> Testing instructions, background context, more in-depth details of the implementation, and anything else you'd like to call out or ask reviewers. Explain how the changes were verified. | ||
## Testing | ||
> Screenshots, GIF demos, code examples or output to help show the changes working as expected. ProTip: you can drag and drop or paste images into this textbox. | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Mac filesystem file | ||
.DS_Store | ||
|
||
|
||
# IDE-specific files | ||
.vscode/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Template Application Flask | ||
|
||
Template application for a basic Flask API. | ||
|
||
This application should run as-is with minimal setup (see below). | ||
## Getting started | ||
|
||
This application is dockerized. Take a look at [Dockerfile](./app/Dockerfile) to see how it works. | ||
|
||
A very simple [docker-compose.yml](./docker-compose.yml) has been included to support local development and deployment. Take a look at [docker-compose.yml](./docker-compose.yml) for more information. | ||
|
||
**How to run:** | ||
|
||
1. In your terminal, `cd` to the app directory of this repo. | ||
2. Make sure you have [Docker Desktop](https://www.docker.com/products/docker-desktop/) installed & running. | ||
3. Run `make init start` to build the image and start the container. | ||
4. Navigate to `localhost:8080/v1/docs` to access the Swagger UI. | ||
5. Run `make run-logs` to see the logs of the running API container | ||
6. Run `make stop` when you are done to delete the container. | ||
|
||
See: [app/README.md](/app/README.md) for further details on the API implementation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Python compiled/optimized files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# Python packaging stuff | ||
dist/ | ||
*.egg-info | ||
|
||
# Python testing stuff | ||
.coverage* | ||
coverage.* | ||
.testmondata | ||
.pytest_cache/ | ||
|
||
# Python environments | ||
.env | ||
.venv | ||
|
||
# mypy | ||
.mypy_cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Spectral rule file to use in Makefile. See: https://meta.stoplight.io/docs/spectral/docs/getting-started/rulesets.md | ||
extends: spectral:oas | ||
|
||
rules: | ||
operation-description: off | ||
no-$ref-siblings: info | ||
path-kebab-case: | ||
description: Paths must be kebab-case. | ||
message: "Path {{property}} must be kebab-case" | ||
severity: warn | ||
given: $.paths[*]~ | ||
then: | ||
function: pattern | ||
functionOptions: | ||
match: "^(\/([a-z0-9-]+|{[^}]+}))+$" | ||
path-param-snake-case: | ||
description: Parameters in paths must be snake_case. | ||
message: "Parameter in path {{property}} must be snake_case" | ||
severity: error | ||
given: $.paths[*]~ | ||
then: | ||
function: pattern | ||
functionOptions: | ||
match: "^(\/([^{^}]+|{[a-z0-9_]+}))+$" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Use the official python3 image based on Debian 11 "Bullseye". | ||
# https://hub.docker.com/_/python | ||
FROM python:3-slim | ||
# Keep container packages up-to-date. | ||
RUN apt update \ | ||
&& apt upgrade --yes | ||
# Install poetry, the package manager. | ||
# https://python-poetry.org | ||
RUN pip install poetry | ||
|
||
|
||
# Set the application working directory. | ||
WORKDIR /srv | ||
|
||
COPY pyproject.toml poetry.lock ./ | ||
RUN poetry config virtualenvs.in-project false && poetry env use python | ||
RUN poetry install --no-root | ||
|
||
# Copy application files. | ||
COPY . /srv | ||
|
||
# Install application dependencies. | ||
# https://python-poetry.org/docs/basic-usage/#installing-dependencies | ||
RUN poetry install | ||
# Run the application. | ||
CMD ["poetry", "run", "python", "-m", "api"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
################################################## | ||
# Constants | ||
################################################## | ||
|
||
APP_NAME := main-app | ||
|
||
# Adding this to the end of a script that outputs JSON will convert | ||
# it to a readable format with timestamps and color-coding. | ||
# | ||
# Note that you can also change the LOG_FORMAT env var to switch | ||
# between JSON & human readable format. This is left in place | ||
# in the event JSON is output from a process we don't log. | ||
DECODE_LOG := 2>&1 | python3 -u api/logging/util/decodelog.py | ||
|
||
# A few commands need adjustments if they're run in CI, specify those here | ||
# TODO - when CI gets hooked up, actually test this. | ||
ifdef CI | ||
DOCKER_EXEC_ARGS := -T -e CI -e PYTEST_ADDOPTS="--color=yes" | ||
FLAKE8_FORMAT := '::warning file=api/%(path)s,line=%(row)d,col=%(col)d::%(path)s:%(row)d:%(col)d: %(code)s %(text)s' | ||
MYPY_FLAGS := --no-pretty | ||
MYPY_POSTPROC := | perl -pe "s/^(.+):(\d+):(\d+): error: (.*)/::warning file=api\/\1,line=\2,col=\3::\4/" | ||
SPECTRAL_POSTPROC := --format=text | perl -pe "s/^\/tmp\/(.+):(\d+):(\d+) (error|warning) (.*)/::warning file=api\/\1,line=\2,col=\3::\4 \5/" | ||
else | ||
FLAKE8_FORMAT := default | ||
endif | ||
|
||
# By default, all python/poetry commands will run inside of the docker container | ||
# if you wish to run this natively, add PY_RUN_APPROACH=local to your environment vars | ||
# You can set this by either running `export PY_RUN_APPROACH=local` in your shell or add | ||
# it to your ~/.zshrc file (and run `source ~/.zshrc`) | ||
ifeq "$(PY_RUN_APPROACH)" "local" | ||
PY_RUN_CMD := poetry run | ||
else | ||
PY_RUN_CMD := docker-compose run $(DOCKER_EXEC_ARGS) --rm $(APP_NAME) poetry run | ||
endif | ||
|
||
################################################## | ||
# API Build & Run | ||
################################################## | ||
|
||
build: | ||
docker-compose build | ||
|
||
start: | ||
docker-compose up --detach | ||
|
||
run-logs: start | ||
docker-compose logs --follow --no-color $(APP_NAME) | ||
|
||
|
||
init: build init-db | ||
|
||
clean-volumes: ## Remove project docker volumes (which includes the DB state) | ||
docker-compose down --volumes | ||
|
||
stop: | ||
docker-compose down | ||
|
||
################################################## | ||
# DB & migrations | ||
################################################## | ||
|
||
######################### | ||
# DB running / setup | ||
######################### | ||
|
||
# Docker starts the image for the DB but it's not quite | ||
# fully ready, so add a 5 second sleep so upgrade doesn't | ||
# fail because the DB hasn't started yet. | ||
init-db: start-db sleep-5 db-upgrade | ||
|
||
start-db: | ||
docker-compose up --detach main-db | ||
|
||
## Destroy current DB, setup new one | ||
db-recreate: clean-docker-volumes init-db | ||
|
||
######################### | ||
# DB Migrations | ||
######################### | ||
|
||
alembic_config := ./api/db/migrations/alembic.ini | ||
alembic_cmd := $(PY_RUN_CMD) alembic --config $(alembic_config) | ||
|
||
db-upgrade: ## Apply pending migrations to db | ||
$(PY_RUN_CMD) db-migrate-up | ||
|
||
db-downgrade: ## Rollback last migration in db | ||
$(PY_RUN_CMD) db-migrate-down | ||
|
||
db-downgrade-all: ## Rollback all migrations | ||
$(PY_RUN_CMD) db-migrate-down-all | ||
|
||
check-migrate-msg: | ||
ifndef MIGRATE_MSG | ||
$(error MIGRATE_MSG is undefined) | ||
endif | ||
|
||
db-migrate-create: check-migrate-msg | ||
$(alembic_cmd) revision --autogenerate -m "$(MIGRATE_MSG)" | ||
|
||
MIGRATE_MERGE_MSG := Merge multiple heads | ||
db-migrate-merge-heads: ## Create a new migration that depends on all existing `head`s | ||
$(alembic_cmd) merge heads -m "$(MIGRATE_MERGE_MSG)" $(args) | ||
|
||
db-migrate-current: ## Show current revision for a database | ||
$(alembic_cmd) current $(args) | ||
|
||
db-migrate-history: ## Show migration history | ||
$(alembic_cmd) history $(args) | ||
|
||
db-migrate-heads: ## Show migrations marked as a head | ||
$(alembic_cmd) heads $(args) | ||
|
||
################################################## | ||
# Testing | ||
################################################## | ||
|
||
test: | ||
$(PY_RUN_CMD) pytest $(args) | ||
|
||
################################################## | ||
# Formatting and linting | ||
################################################## | ||
|
||
format: | ||
$(PY_RUN_CMD) isort --atomic api tests | ||
$(PY_RUN_CMD) black api tests | ||
|
||
lint: lint-spectral lint-py | ||
|
||
lint-py: lint-flake lint-mypy lint-poetry-version | ||
|
||
lint-flake: | ||
$(PY_RUN_CMD) flake8 --format=$(FLAKE8_FORMAT) api tests | ||
|
||
lint-mypy: | ||
$(PY_RUN_CMD) mypy --show-error-codes $(MYPY_FLAGS) api $(MYPY_POSTPROC) | ||
|
||
lint-poetry-version: ## Check poetry version | ||
grep --quiet 'lock-version = "1.1"' poetry.lock | ||
|
||
lint-spectral: | ||
docker run --rm --tty --cap-drop=ALL --network=none --read-only --volume=$(PWD):/tmp:ro \ | ||
stoplight/spectral:6 lint /tmp/openapi.yml --ruleset /tmp/.spectral.yaml $(SPECTRAL_POSTPROC) | ||
|
||
test-coverage: | ||
$(PY_RUN_CMD) coverage run --branch --source=api -m pytest $(args) | ||
$(PY_RUN_CMD) coverage report | ||
|
||
test-coverage-report: ## Open HTML test coverage report | ||
$(PY_RUN_CMD) coverage html --directory .coverage_report | ||
open .coverage_report/index.html | ||
|
||
################################################## | ||
# Scripts | ||
################################################## | ||
|
||
generate-pet-csv: | ||
$(PY_RUN_CMD) generate-pet-csv | ||
|
||
################################################## | ||
# Miscellaneous Utilities | ||
################################################## | ||
|
||
# Pauses for 5 seconds | ||
sleep-5: | ||
sleep 5 |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# If __main__.py is present in a Python module, it will be executed by default | ||
# if that module is executed, e.g., `python -m my.module`. | ||
# | ||
# https://docs.python.org/3/library/__main__.html | ||
|
||
import api.app | ||
import api.logging | ||
from api.app_config import AppConfig | ||
from api.util.local import load_local_env_vars | ||
|
||
logger = api.logging.get_logger(__package__) | ||
|
||
|
||
def main() -> None: | ||
load_local_env_vars() | ||
app_config = AppConfig() | ||
|
||
api.logging.init(__package__) | ||
logger.info("Running API Application") | ||
|
||
app = api.app.create_app() | ||
|
||
if app_config.environment == "local": | ||
# If python files are changed, the app will auto-reload | ||
# Note this doesn't have the OpenAPI yaml file configured at the moment | ||
app.run(port=8080, use_reloader=True, reloader_type="stat") | ||
else: | ||
# Don't enable the reloader if non-local | ||
app.run(port=8080) | ||
|
||
|
||
main() |
Oops, something went wrong.