Integrando uma Web API com Datastore Emulator
Geazi Anc
Posted on February 21, 2023
O custo elevado do faturamento associado aos projetos do Google Cloud Platform (GCP) é algo que sempre devemos ter em mente durante todo o ciclo de desenvolvimento de um produto.
A fim de mitigar esse problema, uma das abordagens é o uso de emuladores que simulam alguns serviços localmente, acarretando em custo zero para o projeto.
Hoje, iremos ver como rodar o emulador oficial do Datastore localmente com Docker, e como integrá-lo com uma Web API!
Desenvolvimento da solução
Iremos desenvolver uma breve solução através do notebook para demonstrar o funcionamento do emulator do Datastore. Para tal, iremos desenvolver uma Web API bem simples que irá se integrar com o Datastore local.
Toda a solução será desenvolvida por meio de contêineres via Docker.
Web API
Desenvolvimento de uma API responsável pelo cadastro de usuários. Os dados serão persistidos localmente no contêiner do Datastore.
-
POST /users
: salva um usuário no Datastore; -
GET /users
: recupera todos os usuários persistidos no Datastore;
Também será desenvolvido um arquivo Dockerfile para fazer a instalação das bibliotecas necessárias e subir o servidor de desenvolvimento da API.
$ mkdir src
$ touch src/app.py
import os
from fastapi import FastAPI
from google.cloud import datastore
from pydantic import BaseModel
PROJECT_ID = os.getenv("DATASTORE_PROJECT_ID")
client = datastore.Client(PROJECT_ID)
app = FastAPI()
class User(BaseModel):
name: str
age: int
@app.post("/users", status_code=201)
def create_user(user: User):
kind = "users"
key = client.key(kind)
user_entity = client.entity(key)
user_entity.update(user)
client.put(user_entity)
return user
@app.get("/users")
def get_users():
query = client.query(kind="users")
users = list(query.fetch())
return users
$ touch requirements.txt
fastapi==0.91.0
uvicorn==0.20.0
google-cloud-datastore==2.13.2
$touch web-api.Dockerfile
FROM python:3.11-alpine
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt
COPY . .
CMD exec python -m uvicorn app:app --reload --app-dir=./src --host=0.0.0.0 --port=8000
Datastore
O desenvolvimento de um contêiner do Datastore consiste nos seguintes passos:
- Desenvolvimento de uma imagem customizada tendo como base a imagem oficial dos emuladores do GCP;
- Iniciar o servidor web do Datastore;
$ touch datastore.Dockerfile
FROM gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators
WORKDIR /datastore
CMD exec gcloud beta emulators datastore start --project my-local-project --host-port 0.0.0.0
Desenvolvimento dos contêineres
Por fim, vamos desenvolver um arquivo docker-compose que irá orquestrar os contêineres construídos com base em nossas imagens.
Nota: observe que é necessário configurar as variáveis de ambiente do Datastore no contêiner da API. Isso se faz necessário para que o SDK do Datastore envie as solicitações diretamente para o contêiner local, não para os servidores do GCP.
$ touch docker-compose.yml
version: '3.9'
services:
web-api:
build:
dockerfile: ./web-api.Dockerfile
environment:
DATASTORE_DATASET: my-local-dataset
DATASTORE_EMULATOR_HOST: datastore:8081
DATASTORE_EMULATOR_HOST_PATH: datastore:8081/datastore
DATASTORE_HOST: http://datastore:8081
DATASTORE_PROJECT_ID: my-local-project
volumes:
- ./:/app
ports:
- 8000:8000
datastore:
build:
dockerfile: ./datastore.Dockerfile
ports:
- 8081:8081
$ docker compose up -d
$ docker compose ps
Vamos testar!
Iremos fazer três solicitações para nossa API. As duas primeiras serão solicitações POST, que irá salvar dois usuários no Datastore, e a última será uma solicitação GET que irá recuperar os dois usuários persistidos no banco de dados.
$ curl -X 'POST' \
'http://localhost:8000/users' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"name": "John",
"age": 20
}'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 57 100 24 100 33 54 75 --:--:-- --:--:-- --:--:-- 130
{"name":"John","age":20}
$ curl -X 'POST' \
'http://localhost:8000/users' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"name": "Mary",
"age": 18
}'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 57 100 24 100 33 1411 1941 --:--:-- --:--:-- --:--:-- 3352
{"name":"Mary","age":18}
$ curl -X 'GET' \
'http://localhost:8000/users' \
-H 'accept: application/json'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 51 100 51 0 0 850 0 --:--:-- --:--:-- --:--:-- 850
[{"name":"John","age":20},{"name":"Mary","age":18}]
Considerações finais
O uso dos emuladores do Google Cloud Platform podem ser uma abordagem interessante durante o ciclo de desenvolvimento de um produto. Com eles, podemos testar nossas soluções quantas vezes forem necessárias sem acarretar em um custo elevado no faturamento do projeto, visto que todas as solicitações das bibliotecas do Google Cloud serão feitas localmente ao invés de serem feitas para os servidores da nuvem.
Obrigado por ter me acompanhado até aqui 💚. Até a próxima!
Referências
Posted on February 21, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.