Skip to content

Commit

Permalink
Merge pull request #19 from rafsaf/release-3-1
Browse files Browse the repository at this point in the history
Release 3.1, updated readme and dependencies. Fixed issue with allowed hosts.
  • Loading branch information
rafsaf authored Oct 19, 2022
2 parents e820c9b + 235ce93 commit 1cce9d3
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 415 deletions.
100 changes: 83 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@

# Minimal async FastAPI + PostgreSQL template

- [Feauters](#features)
- [Quickstart](#quickstart)
- [About](#about)
- [Step by step example - POST and GET endpoints](#step-by-step-example---post-and-get-endpoints)
- [1. Create SQLAlchemy model](#1-create-sqlalchemy-model)
- [2. Create and apply alembic migration](#2-create-and-apply-alembic-migration)
- [3. Create request and response schemas](#3-create-request-and-response-schemas)
- [4. Create endpoint](#4-create-endpoints)
- [5. Write tests](#5-write-tests)
- [Deployment strategies - via Docker image](#deployment-strategies---via-docker-image)
- [Minimal async FastAPI + PostgreSQL template](#minimal-async-fastapi--postgresql-template)
- [Features](#features)
- [Quickstart](#quickstart)
- [1. Install cookiecutter globally and cookiecutter this project](#1-install-cookiecutter-globally-and-cookiecutter-this-project)
- [2. Install dependecies with poetry or without it](#2-install-dependecies-with-poetry-or-without-it)
- [3. Setup databases](#3-setup-databases)
- [4. Now you can run app](#4-now-you-can-run-app)
- [Running tests](#running-tests)
- [About](#about)
- [Step by step example - POST and GET endpoints](#step-by-step-example---post-and-get-endpoints)
- [1. Create SQLAlchemy model](#1-create-sqlalchemy-model)
- [2. Create and apply alembic migration](#2-create-and-apply-alembic-migration)
- [3. Create request and response schemas](#3-create-request-and-response-schemas)
- [4. Create endpoints](#4-create-endpoints)
- [5. Write tests](#5-write-tests)
- [Deployment strategies - via Docker image](#deployment-strategies---via-docker-image)
- [Docs URL, CORS and Allowed Hosts](#docs-url-cors-and-allowed-hosts)

## Features

Expand All @@ -47,8 +54,9 @@ _Check out also online example: https://minimal-fastapi-postgres-template.rafsaf

## Quickstart


### 1. Install cookiecutter globally and cookiecutter this project
```bash
# Install cookiecutter globally
pip install cookiecutter

# And cookiecutter this project :)
Expand All @@ -57,21 +65,39 @@ cookiecutter https://github.com/rafsaf/minimal-fastapi-postgres-template
# if you want experimental fastapi-users template
# check "experimental_fastapi_users_template"
# to True in cookiecutter option
```

### 2. Install dependecies with poetry or without it
```bash
cd project_name
# Poetry install (and activate environment!)
### Poetry install (python3.10)
poetry install
# Setup two databases

### Optionally there are also requirements
python3.10 -m venv venv
source venv/bin/activate
pip install -r requirements-dev.txt
```
Note, be sure to use `python3.10` with this template with either poetry or standard venv & pip, if you need to stick to some earlier python version, you should adapt it yourself (remove python3.10+ specific syntax for example `str | int`)

### 3. Setup databases
```bash
### Setup two databases
docker-compose up -d
# Alembic migrations upgrade and initial_data.py script

### Alembic migrations upgrade and initial_data.py script
bash init.sh
# And this is it:
```
### 4. Now you can run app
```bash
### And this is it:
uvicorn app.main:app --reload

# Optionally - use git init to initialize git repository
```
You should then use `git init` to initialize git repository and access OpenAPI spec at http://localhost:8000/ by default. To customize docs url, cors and allowed hosts settings, read section about it.


#### Running tests
### Running tests

```bash
# Note, it will use second database declared in docker-compose.yml, not default one
Expand Down Expand Up @@ -355,3 +381,43 @@ This template has by default included `Dockerfile` with [Nginx Unit](https://uni
`nginx-unit-config.json` file included in main folder has some default configuration options, runs app in single process and thread. More info about config file here https://unit.nginx.org/configuration/#python and about also read howto for FastAPI: https://unit.nginx.org/howto/fastapi/.

If you prefer other webservers for FastAPI, check out [Daphne](https://github.com/django/daphne), [Hypercorn](https://pgjones.gitlab.io/hypercorn/index.html) or [Uvicorn](https://www.uvicorn.org/).

## Docs URL, CORS and Allowed Hosts

There are some **opinionated** default settings in `/app/main.py` for documentation, CORS and allowed hosts.

1. Docs

```python
app = FastAPI(
title=config.settings.PROJECT_NAME,
version=config.settings.VERSION,
description=config.settings.DESCRIPTION,
openapi_url="/openapi.json",
docs_url="/",
)
```
Docs page is simpy `/` (by default in FastAPI it is `/docs`). Title, version and description are taken directly from `config` and then directly from `pyproject.toml` file. You can change it completely for the project, remove or use environment variables `PROJECT_NAME`, `VERSION`, `DESCRIPTION`.

2. CORS

```python
app.add_middleware(
CORSMiddleware,
allow_origins=[str(origin) for origin in config.settings.BACKEND_CORS_ORIGINS],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
```

If you are not sure what are CORS for, follow https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS. React and most frontend frameworks nowadays operate on `localhost:3000` thats why it's included in `BACKEND_CORS_ORIGINS` in .env file, before going production be sure to include and frontend domain here, like `my-fontend-app.example.com`

3. Allowed Hosts

```python
app.add_middleware(TrustedHostMiddleware, allowed_hosts=config.settings.ALLOWED_HOSTS)
```

Prevents HTTP Host Headers attack, you shoud put here you server IP or (preferably) full domain under it's accessible like `example.com`. By default in .env there are two most popular records: `ALLOWED_HOSTS=["localhost", "127.0.0.1"]`

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ENVIRONMENT=DEV
ACCESS_TOKEN_EXPIRE_MINUTES=11520
REFRESH_TOKEN_EXPIRE_MINUTES=40320
BACKEND_CORS_ORIGINS=["http://localhost:3000","http://localhost:8001"]
ALLOWED_HOSTS=["localhost"]
ALLOWED_HOSTS=["localhost", "127.0.0.1"]

DEFAULT_DATABASE_HOSTNAME=localhost
DEFAULT_DATABASE_USER=rDGJeEDqAz
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ENVIRONMENT=DEV
ACCESS_TOKEN_EXPIRE_MINUTES=11520
REFRESH_TOKEN_EXPIRE_MINUTES=40320
BACKEND_CORS_ORIGINS=["http://localhost:3000","http://localhost:8001"]
ALLOWED_HOSTS=["localhost"]
ALLOWED_HOSTS=["localhost", "127.0.0.1"]

DEFAULT_DATABASE_HOSTNAME=localhost
DEFAULT_DATABASE_USER=postgres
Expand Down
2 changes: 1 addition & 1 deletion {{cookiecutter.project_name}}/template_minimal/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# See https://unit.nginx.org/installation/#docker-images

FROM nginx/unit:1.26.1-python3.10
FROM nginx/unit:1.28.0-python3.10

ENV PYTHONUNBUFFERED 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Settings(BaseSettings):
ACCESS_TOKEN_EXPIRE_MINUTES: int = 11520 # 8 days
REFRESH_TOKEN_EXPIRE_MINUTES: int = 40320 # 28 days
BACKEND_CORS_ORIGINS: list[AnyHttpUrl] = []
ALLOWED_HOSTS: list[str] = ["localhost"]
ALLOWED_HOSTS: list[str] = ["localhost", "127.0.0.1"]

# PROJECT NAME, VERSION AND DESCRIPTION
PROJECT_NAME: str = PYPROJECT_CONTENT["name"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ services:
- .env
environment:
- DEFAULT_DATABASE_HOSTNAME=postgres
- DEFAULT_DATABASE_PORT=5432
ports:
- 80:80

Expand Down
Loading

0 comments on commit 1cce9d3

Please sign in to comment.