v2.0

Postado em: 29-11-2022 às 10:37:49 PM · 9 min de leitura

[DESATUALIZADO] API Simples com FastAPI e dando deploy com Deta CLI


Este é o primeiro post do blog do site, e como tal resolvi transcrever uma aula/palestra que ministrei, a qual aborda o desenvolvimento de uma API em Python e subir a aplicação no serviço do Deta Micro. Antes de começar, vamos entender o que é uma API REST.

Uma API REST basicamente é um conjunto de restrições definidas para o comportamento da interface de comunicação de equisições http para aplicações que trabalham com dados com o servidor. Desta forma, uma api rest permite um comportamento “padrão” restrito para uma aplicação executar determinadas operações com a API.

Uma API REST em suma, é representada pelas quatro operações básicas no tratamento de dados: CREATE, READ, UPDATE, DELETE. (CRUD). No caso das REST API’s, o comportamento é definido na requisição do cabeçalho http, utilizado os seguintes principais: GET, POST, PUT, DELETE. 


Instalando os componentes e estruturando o projeto

FastAPI é um micro framework para python, usado para criar api’s REST simples, com ele é possível criar uma API RESTful com poucas linhas de código. Pode-se dizer que seu uso tão simples como o Framework Python Web Flask. Para dar seguimento, vamos estrutura nosso projeto da seguinte forma para facilitar o trabalho futuro.

|-- app
| |---- database
| | |---- __init__.py
| | |---- db_con.py
| |---- models
| | |---- __init__.py
| | |---- models.py
| |---- routers
| | |---- __init__.py
| | |---- api.py
| |----__init__.py
| |---- config.py
|---- .env
|---- main.py
|---- requirements.txt

Nota*: O FastAPI não possui uma ‘arquitetura de projeto’ definida, isso dependerá da aplicação. Para aplicações que são grandes, o mais indicado seria utilizar uma alternativa mais robusta,  

Antes também devemos instalar as seguintes dependencias (deta, fastapi e uvicorn e a python-dotenv), é possivel fazer isso simplismente criando um arquivo requirements.txt e colar a informação abaixo e rodar o comando  pip install -r requirements.txt, lembre-se sempre de salvar o seu requirements.txt em formato UTF-8, caso você tenha criado ele manualmente.

deta==0.7
fastapi==0.61.2
python-dotenv==0.19.2
uvicorn==0.12.2

Para começar a utilizar primeiro é importante ter o Python instalado e depois é só instalar o módulo com o comando pip install fastapi e criar o seu arquivo main.py. 

from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
	return {"Hello": "World"}

Em seguida, rode o seguinte comando uvicorn main:app --host 0.0.0.0 --port 80 --reload no terminal que o seu primeiro projeto em FastAPI irá ser iniciado. Basta digitar no navegador ou no seu programa do Postmam ou Insomnia e fazer a requisição do tipo GET na rota http://0.0.0.0:80/ ou simplismente http://localhost:80/.

Criando os modelos da API

from typing import Optional, List
from pydantic import BaseModel, Field
from datetime import datetime
class Leitura(BaseModel):
	sensor: Optional[str] = Field(None, example="Sensor Name")
	desc: Optional[str] = None
	status: Optional[List['str']] = Field([], example=[ "Leitura 1", "Leitura 2", "..."])
	data_hora: int = int(datetime.timestamp(datetime.now()) * 1000)
	
	class Config: # somente para documentação
		schema_extra = {
			"example": {
				"sensor": "DHT11",
				"desc": "Monitorando...",
				"status": [
					"Temperatura: 30.0 ºC",
					"Umidade: 60%"
				]
			}
		}

Crie o modelo acima em seu arquivo models.py, o modelo apresenta atributos que irão compor o nosso Payload Json na requisição, além disso temos diferentes atribuições para cada um dos atributos, por exemplo: 

  • O atributo sensor, é opcional de ser passado, sendo do tipo string, tendo campo padrão como None (tipo null em python);
  • O atributo desc, é opcional de ser passado, sendo do tipo string, iniciando com None;
  • O atributo status é opcional, sendo uma lista de strings, além disso começa sempre como uma string vazia;
  • O atributo data_hora, é do tipo inteiro, e sempre é iniciado quando o objeto é criado;
  • A classe interna Config, serve apenas para documentação dos nossos models na API, assim como os atributos 'examples';

Deta Base

Agora que temos os nossos modelos, antes de dar prosseguimento na aplicação, devemos criar uma conta no Deta para poder ter acesso a criação de projetos e usar o Deta Base, e também instalar o Deta CLI pra fazer deploy da nossa API. Com o Deta Base é possível salvar dados na nuvem no formato de documentos NoSQL de forma simples e fácil, apesar das limitações no numeros de requisições e do tempo entre elas (Veja sempre a documentação). 

Após criar a conta no Deta, crie um projeto e nele será exibida uma key, Não apenas isso é necessário anotar a project key que será criada para acessar o projeto e salvá-la em um lugar seguro pois ela só é exibida uma única vez. A key de um projeto será algo parecido com a figura abaixo, é possivel criar outras chaves no futuro, entretando elas também só serão visíveis uma única vez.

 
A chave acima já foi deletada, então não adianta copia-la :)
 

Agora no arquivo .env do nosso projeto, vamos adicionar os seguintes valores para serem as nossas variáveis de ambiente.

  • VAR_DETA_BASE_NAME=YOUR_BASE_NAME
    • Esta será a base onde salvaremos os nossos dados
  • VAR_DETA_PROJECT_KEY=YOUR_PROJECT_KEY
    • A nossa Project Key
  • VAR_DETA_PROJECT_ID=YOUR_PROJECT_ID
    • Nosso Project ID (Acessável pelo próprio projeto, ou simplismente o valor que precede o underline na project key)

Para usar essas variáveis localmente no nosso projeto, sem precisar defini-las no sistema, vamos usar o python dotenv que instalamos, no nosso arquivo config.py adicionaremos o seguinte.

import os
from dotenv import load_dotenv # Usar só localmente, devendo ser desconciderado ao dar deploy
load_dotenv() # Lê o arquivo .env
DETA_BASE_NAME = os.getenv("VAR_DETA_BASE_NAME")
DETA_PROJECT_KEY = os.getenv("VAR_DETA_PROJECT_KEY")
DETA_PROJECT_ID = os.getenv("VAR_DETA_PROJECT_ID")

Desta forma é possivel usar as variáveis criadas no nosso arquivo .env localmente, com isso feito vamos dar prosseguimento ao desenvolvimento da nossa API para em seguida usar o Deta CLI, no nosso arquivo api.py vamos adicionar uma forma de criar nossas rotas e dizer que queremos usar o nosso model 'Leitura' como Payload. Vamos criar quatro funções que irão representar nosso CRUD.

from ..models.models import Leitura
from .config import DETA_BASE_NAME, DETA_PROJECT_KEY, DETA_PROJECT_ID
from typing import List
from fastapi.routing import APIRouter
 
# Instancia da nossa base do Deta pra salvar nossos dados, definindo os parametros pelo nosso arquivo config.py
_api_base: Base = Deta(
    project_key=DETA_PROJECT_KEY,
    project_id=DETA_PROJECT_ID
).Base(DETA_PROJECT_BASE)
 
# rota para a nossa API do FastAPI
router: APIRouter = APIRouter() 
	
@router.get('/', status_code=200, response_model=List[Leitura])
async def method_get():
    """
    Busca e retorna todos os objectos do deta base
    :returns: json
    """
    return next(_api_base.fetch())
    
@router.put('/{key}', status_code=201)
async def method_put(key: str, msg: Leitura)
    """
    Busca e atualiza uma instância de um objeto do deta base
    :returns: json
    """
    _finded = _api_base.get(key)
    to_update = MessageExample(**(_finded if _finded != None else {}))
    new_data = msg.dict(exclude_unset=True)
    updated = to_update.copy(update=new_data)
    return _api_base.put(updated.dict(), key)
    
@router.post('/', status_code=201)
async def method_post(msg: Leitura):
    """
    insere um novo valor no deta base
    :returns: json
    """
    return _api_base.insert(msg.dict())
    
@router.delete('/{key}', status_code=204)
async def method_delete(key: str):
    """
    deleta um documento do deta base pela key
    """
    _api_base.delete(key)

No nosso main.py adicionaremos algumas coisas, primeiro vamos criar uma função para criar o objeto do nosso app, além disso, devemos usar as seguintes configurações do CORS, de modo a permitir que as rotas da aplicação possam ser acessadas por qualquer endereço caso dermos deploy nela mais tarde. Em seguida adicionamos a rota principal da nossa api e colocamos o prefixo ‘/api’, assim para acessar a rota base ‘/’ da api com o GET request, ao rodarmos o comando uvicorn main:app --host 0.0.0.0 --port 80 --reload, vamos acessar da seguinte forma, http://0.0.0.0:80/api ou simplismente http://localhost:80/api.

from .routers.api import router as api_router
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
def create_app():
    _app = FastAPI()
    _app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    _app.include_router(api_router, prefix='/api')
    return _app
app = create_app()

Deploy no Deta Micro com o Deta CLI

Com o Deta CLI instalado, vamos primeiro nos autenticar com o comando deta login, após logar na pagina na raiz do teu projeto digite o comando deta new --project <PROJECT-NAME> , onde o <PROJECT-NAME> sendo o nome do seu projeto no deta, com isso irá gerar uma pasta chamada .deta, e o terminal irá exibir a seguinte saída. 

Successfully created a new micro
{
	"name": <project-micro-name>,
	"id": <project-id-micro>,
	"project": <project-id>,
	"runtime": <python-micro-version>,
	"endpoint": "https://<al-name>.deta.dev",
	"region": <project-region>,
	"visor": "enabled",
	"http_auth": "disabled"
}
Adding dependencies...

* Nota: Lembre-se de que o arquivo requirements.txt deve estar em UTF-8 para poder adicionar as dependências.

Agora seu ambiente micro estará online, entretanto não irá funcionar corretamente, devemos adicionar as nossas varáveis de ambiente no deta, para isso usamos o comando deta update --env .env onde o .env é o nosso arquivo que contém as nossas variáveis de ambiente. Com isso, agora o deta sabe quais variáveis usar. Em seguida, usamos o comando deta deploy para dar deploy do nosso app ao deta, para obter ajuda com os os comandos do Deta CLI, é possivel obter com o comando deta -h ou acessando a Documentação do Deta . Agora recarregue a pagina do seu projeto no deta, que é possivel observar algo semelhante a isso ao acessar a sua aba de micro serviços: 

 
No canto superior direito, estará o link gerado para a sua API online, onde você poderá acessá-la.
 

Atualmente, após algumas atualizações os projetos tem uma memória reservada maior, além do deta suportar bibliotecas para micro serviços feitos com Python e em Node.js, entretanto não possui suporte a todas as funcionalidades de algumas dependências, já que possui algumas limitações. O Deta é uma escolha agradável para quem deseja colocar ou testar uma API ou um micro serviço online, sem esforço e sem custo, e que permanecerá assim por um bom tempo (segundo os criadores é claro). Sendo uma boa alternativa para projetos ‘pequenos’ ou testar funcionalidades. Inclusive, na data de atualização desta postagem, este site se encontra hospedado usando o serviços do deta micro ¯\_(ツ)_/¯. 

Tags:
Posts relacionados
Portainer e NGINX
Redes Neurais e algoritmos genéticos - Joguinhos simples
ESP8266 Projeto - Consultando cotações em APIs de criptomoedas
NodeMCU ESP8266 - As placas para IoT