FastAPI é um framework Python moderno, projetado para simplicidade, velocidade e eficiência. A combinação de diversas funcionalidades modernas do Python como anotações de tipo e suporte a concorrência, facilitando o desenvolvimento de APIs.
Verificando a instalação do Python.
python --version
Instalação do pyenv no Windows, recomendo usar o pyenv-windows.
Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"
Após o pyenv-windows instalado, verificar qual versão do python deseja e instale.
pyenv update
pyenv install 3.12:latest
Definiar uma versão global do Python.
pyenv global 3.12.x
Instalação de ferramentas recomendadas.
pip install pipx
pipx install poetry
Após o poetry instalado é necessário executar o comando abaixo, feche e reabra o terminal:
pipx ensurepath
pipx install ignr
Entrar no diretório onde criará o projeto.
cd C:\projetos\projetos-GIT\
Criando o projeto.
poetry new fast_zero_v2
Entrar no projeto.
cd fast_zero_v2
Definir qual a versão do Python será utilizada nesse projeto/diretório. O script abaixo criará um arquivo que contém a versão do Python.
pyenv local 3.12.4
Esse comando criará um arquivo oculto chamado .python-version
na raiz do projeto.
Configurar o arquivo pyproject.toml
.
[...]
Crie o ambiente virtual do projeto.
poetry install
Instalando a biblioteca Python do FastAPI.
poetry add fastapi
Criação do app.
echo > fast_zero_v2/app.py
[melhorar esta criação pelo terminal]
Acessando e codificando no app.
code fast_zero_v2/app.py
[... codificando ...]
Executar a função pelo terminal em modo interativo para chamar a função.
python -i .\fast_zero_v2\app.py
Depois execute a função para obter o resultado.
>>> read_root()
[... codificando ...]
Antes de iniciar a aplicação, habilitar o ambiente virtual, para que o python consiga enxergar as dependências instaladas.
poetry shell
fastapi dev fast_zero_v2/app.py
poetry add --group dev pytest pytest-cov taskipy ruff httpx
Após a instalação das ferramentas de desenvolvimento, precisamos definir as configurações de cada uma individualmente no arquivo pyproject.toml
.
[... atentar para os nomes dos projetos que influencia neste arqvuivo ...]
Após arquivo configurado, pode testar os comandos criados para o taskipy:
task lint
task format
task lint
task test
Gera um relatório de cobertura de testes em formato HTML. Pode abrir esse arquivo no navegador e entender exatamente quais linhas do código não estão sendo testadas.
coverage html
Criação dos arquivos de teste.
echo > tests/test_app.py
[...]
task test
Por não coletar nenhum teste, o pytest ainda retornou um "erro". Para ver a cobertura, precisaremos executar novamente o post_test manualmente:
task post_test
[... deu muito ruim nessa parte do git, refazer outro projeto com cuidado]
Criar um arquivo .gitignore
para não adicionar o ambiente virtual e outros arquivos desnecessários no versionamento de código.
ignr -p python > .gitignore
Criar um novo repositório no Git local para versionar o código e definir a branch main como padrão.
git init -b main
Para criar um repositório remoto no GitHub externo caso não exista.
gh repo create
- Create a new repository on GitHub from scratch
- fast_zero_sync_v2
- Código das aulas aprendidas no curso do Dunossauro (FASTAPI)
- Public
- N
- N
- y
- GNU General Public License v3.0
- Y
- Y
git remote add origin https://github.com/LuizPerciliano/fast_zero_sync_v2.git
git pull origin main
git add .
git commit -m "Configuração inicial do projeto"
git push
[... deu muito ruim nessa parte do git, refazer outro projeto com cuidado]
fastapi dev fast_zero_v2/app.py --host 0.0.0.0
ou com o comando abaixo para o mesmo resultado
task run --host 0.0.0.0
Assim, você pode acessar a aplicação de outro computador na sua rede usando o endereço IP da sua máquina.
Descobrindo o ip local no Windows
ipconfig
Descobrindo o seu endereço local usando python pelo interpretador
python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
s.getsockname()[0]
Agora basta acessar a aplicação pelo endereço: http://192.168.0.5:8000/, ficando acessível também por outras máquinas dentro dessa rede, assim como o celular.
[... desenvolvendo e incrementando o projeto ...]
Criando novo arquivo para testes e aprendizado de endpoints.
type nul > fast_zero_v2/aula_00.py
Abrir o arquivo fast_zero_v2/aula_00.py
e copiar o script abaixo.
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get('/')
def read_root():
return {'message': 'Olá Mundo!'}
Executar o arquivo específico.
fastapi dev fast_zero_v2/aula_00.py
echo > fast_zero_v2/schemas.py
[... desenvolvendo e incrementando o projeto ...]
Arquivo fast_zero_v2/app.py
.
@app.post('/users/', status_code=HTTPStatus.CREATED)
def create_user():
...
Arquivo fast_zero_v2/schemas.py
.
class UserSchema(BaseModel):
username: str
email: str
password: str
[... desenvolvendo e incrementando o projeto ... estudar mais esta aula]
Validação de email Instalando + ferramentas de desenvolvimento
poetry add "pydantic[email]"
Arquivo tests/conftest.py
.
echo > tests/conftest.py
[🐍 ... VOLTAR DAQUI ...🐍]
Instalando + ferramentas de desenvolvimento
poetry add sqlalchemy
poetry add pydantic-settings
Agora definiremos nosso modelo User. No diretório fast_zero, crie um novo arquivo chamado models.py e incluiremos o seguinte código no arquivo:
echo > fast_zero_v2/models.py
[...]
Criaremos uma fixture para a conexão com o banco de dados chamada session no arquivo tests/conftest.py
.
[...]
Agora, no arquivo test_db.py, escreveremos um teste para a criação de um usuário. Este teste adiciona um novo usuário ao banco de dados, faz commit das mudanças, e depois verifica se o usuário foi devidamente criado consultando-o pelo nome de usuário. Se o usuário foi criado corretamente, o teste passa. Caso contrário, o teste falha, indicando que há algo errado com nossa função de criação de usuário.
echo > tests/test_db.py
[...]
exit
task format
task test
O ideal é ter pelo menos dois terminais ativos, um para rodar a aplicação e outro para os testes e demais comandos.
task run
echo > fast_zero_v2/settings.py
[...]
Agora, definiremos o DATABASE_URL no nosso arquivo de ambiente .env. Crie o arquivo na raiz do projeto e adicione a seguinte linha:
echo > .env
[...]
echo 'database.db' >> .gitignore
poetry add alembic
Após a instalação do Alembic, precisamos iniciá-lo em nosso projeto. O comando de inicialização criará um diretório migrations e um arquivo de configuração alembic.ini:
alembic init migrations
Com o Alembic devidamente instalado e iniciado, agora é o momento de gerar nossa primeira migração. Mas, antes disso, precisamos garantir que o Alembic consiga acessar nossas configurações e modelos corretamente. Para isso, faremos algumas alterações no arquivo migrations/env.py. [...]
Para criar a migração, utilizamos o seguinte comando:
alembic revision --autogenerate -m "create users table"
Vamos abrir e analisar o arquivo de migração migrations/versions/f3577cecc9f1_create_users_table.py
.
code migrations/versions/f3577cecc9f1_create_users_table.py
Vamos acessar o console do sqlite e verificar se isso foi feito. Precisamos chamar sqlite3 nome_do_arquivo.db ou usar uma aplicativo que abre diversos tipos de banco de dados como o DBeaver:
sqlite3 database.db
[...]
Para aplicar as migrações, usamos o comando upgrade do CLI Alembic. O argumento head indica que queremos aplicar todas as migrações que ainda não foram aplicadas:
alembic upgrade head
[...]
Agora, se examinarmos nosso banco de dados novamente: [...]
Primeiro, verificaremos o status do nosso repositório para ver as mudanças que fizemos:
git status
git add .
git commit -m "Adicionada a primeira migração com Alembic. Criada tabela de usuários."
git push
[🐍 ... VOLTAR DAQUI ...🐍]
[...]
Para gerar tokens JWT, precisamos de duas bibliotecas extras: pyjwt e pwdlib. A primeira será usada para a geração do token, enquanto a segunda será usada para criptografar as senhas dos usuários. Para instalá-las, execute o seguinte comando no terminal:
poetry add pyjwt "pwdlib[argon2]"
A classe OAuth2PasswordRequestForm é uma classe especial do FastAPI que gera automaticamente um formulário para solicitar o username (email neste caso) e a senha. Este formulário será apresentado automaticamente no Swagger UI e Redoc, facilitando a realização de testes de autenticação. Para usar os formulários no FastAPI, precisamos instalar o python-multipart:
poetry add python-multipart
Atualizando o repositório.
Agora, precisamos adicionar estes valores ao nosso arquivo .env.
DATABASE_URL="sqlite:///database.db"
SECRET_KEY="your-secret-key"
ALGORITHM="HS256"
ACCESS_TOKEN_EXPIRE_MINUTES=30
Atualizando o repositório.
git add .
git commit -m "Refatorando estrutura do projeto: Criado routers para Users e Auth; movido constantes para variáveis de ambiente."
poetry add --group dev factory-boy
poetry add --group dev freezegun
Atualizando o repositório.
git add .
git commit -m "Implementando o refresh do token e testes de autorização"
alembic revision --autogenerate -m "create todos table"
Depois que a migração for criada, precisamos aplicá-la ao nosso banco de dados. Execute o comando alembic upgrade head para aplicar a migração.
alembic upgrade head
Atualizando o repositório.
git add .
git commit -m "Implementado os endpoints de tarefas"
Para criar um container Docker, escrevemos uma lista de passos de como construir o ambiente para execução da nossa aplicação em um arquivo chamado Dockerfile. Ele define o ambiente de execução, os comandos necessários para preparar o ambiente e o comando a ser executado quando um contêiner é iniciado a partir da imagem.
Uma das coisas interessantes sobre Docker é que existe um Hub de containers prontos onde a comunidade hospeda imagens "prontas", que podemos usar como ponto de partida. Por exemplo, a comunidade de python mantém um grupo de imagens com o ambiente python pronto para uso. Podemos partir dessa imagem com o python já instalado adicionar os passos para que nossa aplicação seja executada.
Aqui está um exemplo de Dockerfile para executar nossa aplicação:
FROM python:3.12-slim
ENV POETRY_VIRTUALENVS_CREATE=false
WORKDIR app/
COPY . .
RUN pip install poetry
RUN poetry config installer.max-workers 10
RUN poetry install --no-interaction --no-ansi
EXPOSE 8000
CMD poetry run uvicorn --host 0.0.0.0 fast_zero.app:app
Para criar uma imagem Docker a partir do Dockerfile, usamos o comando docker build. O comando a seguir cria uma imagem chamada "fast_zero":
docker build -t "fast_zero" .
Então verificaremos se a imagem foi criada com sucesso usando o comando:
docker images
docker run -it --name fastzeroapp -p 8000:8000 fast_zero:latest
curl http://localhost:8000
docker run -d \
--name app_database \
-e POSTGRES_USER=app_user \
-e POSTGRES_DB=app_db \
-e POSTGRES_PASSWORD=app_password \
-p 5432:5432 \
postgres
No PostgreSQL, o diretório padrão para armazenamento de dados é /var/lib/postgresql/data. Mapeamos esse diretório para um volume (neste caso "pgdata") em nossa máquina host para garantir a persistência dos dados:
docker run -d \
--name app_database \
-e POSTGRES_USER=app_user \
-e POSTGRES_DB=app_db \
-e POSTGRES_PASSWORD=app_password \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 \
postgres
poetry add "psycopg[binary]"
Para ajustar a conexão com o PostgreSQL, modifique seu arquivo .env para incluir a seguinte string de conexão:
DATABASE_URL="postgresql+psycopg://app_user:app_password@localhost:5432/app_db"
Para que a instalação do psycopg esteja na imagem docker, precisamos fazer um novo build. Para que a nova versão do pyproject.toml seja copiada e os novos pacotes sejam instalados:
docker rm fastzeroapp
docker build -t "fast_zero"
docker run -it --name fastzeroapp -p 8000:8000 fast_zero:latest
docker exec -it fastzeroapp poetry run alembic upgrade head
Criação do compose.yaml
services:
fastzero_database:
image: postgres
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_USER: app_user
POSTGRES_DB: app_db
POSTGRES_PASSWORD: app_password
ports:
- "5432:5432"
fastzero_app:
image: fastzero_app
build: .
ports:
- "8000:8000"
depends_on:
- fastzero_database
environment:
DATABASE_URL: postgresql+psycopg://app_user:app_password@fastzero_database:5432/app_db
volumes:
pgdata:
docker-compose up
Criamos um script chamado entrypoint.sh que irá preparar nosso ambiente antes de a aplicação iniciar:
#!/bin/sh
# Executa as migrações do banco de dados
poetry run alembic upgrade head
# Inicia a aplicação
poetry run uvicorn --host 0.0.0.0 --port 8000 fast_zero.app:app
Incluímos o entrypoint no nosso serviço no arquivo compose.yaml, garantindo que esteja apontando para o script correto:
compose.yaml
fastzero_app:
image: fastzero_app
entrypoint: ./entrypoint.sh
build: .
docker-compose up --build
docker-compose up -d fastzero_database
poetry add --group dev testcontainers
Atualizando o repositório.
git add .
git commit -m "Dockerizando nossa aplicação e inserindo o PostgreSQL"
git push
Configurando o workflow de CI As configurações dos workflows no GitHub Actions são definidas em um arquivo YAML localizado em um path especificado pelo github no repositório .github/workflows/. Dentro desse diretório podemos criar quantos workflows quisermos. Iniciaremos nossa configuração com um único arquivo que chamaremos de pipeline.yaml:
name: Pipeline
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Instalar o python
uses: actions/setup-python@v5
with:
python-version: '3.12'
Para isso, devemos criar um step para cada uma dessas ações no nosso job test. Desta:
.github/workflows/pipeline.yaml
steps:
- name: Instalar o python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Instalar o poetry
run: pipx install poetry
- name: Instalar dependências
run: poetry install
- name: Executar testes
run: poetry run task test
Atualizando o repositório.
git add .
git commit -m "Adicionando o checkout ao pipeline"
git push
[...]
gh secret set -f .env
.github/workflows/pipeline.yaml
jobs:
test:
runs-on: ubuntu-latest
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
ALGORITHM: ${{ secrets.ALGORITHM }}
ACCESS_TOKEN_EXPIRE_MINUTES: ${{ secrets.ACCESS_TOKEN_EXPIRE_MINUTES }}
Atualizando o repositório.
git add .
git commit -m "Adicionando as variáveis de ambiente para o CI"
git push
[...]
git add .
git commit -m "Adicionando arquivos gerados pelo Fly"
git push
[... ainda vai ter esta aula ...]
XXX
s = "Sintaxe do Pythong"
print s