Ferramentas/AjustaFundos/packages/v1/api/Mirror/actions/api_action.py

194 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import re
from actions.env.mirror_sync_env import MirrorSyncEnv
from actions.file.file_name_generator import FileNameGenerator
from actions.file.json_file_saver import JsonFileSaver
import httpx
from actions.data.dict_to_obj import DictToObj
from actions.ui.ui import fail, ok, rule
class ApiAction:
def __init__(self) -> None:
self.file_name_generator = FileNameGenerator()
# Classe para obter as variaveis de ambiente
mirror_sync_env = MirrorSyncEnv()
# Obtem as variaveis de ambiente em formato de objeto
self.mirror_sync_env = mirror_sync_env.as_object()
pass
def sanitize_unicode(self, data):
"""
Remove caracteres inválidos (surrogates) de strings dentro de estruturas complexas.
"""
if isinstance(data, str):
# Remove caracteres Unicode no intervalo D800DFFF (não permitidos em UTF-8)
return re.sub(r"[\ud800-\udfff]", "", data)
elif isinstance(data, list):
return [self.sanitize_unicode(i) for i in data]
elif isinstance(data, dict):
return {k: self.sanitize_unicode(v) for k, v in data.items()}
return data
# Cria os Cabeçalhos de envio
def _headers(self, data):
headers = {
"Accept": getattr(data, "accept", "application/json"),
"Content-Type": getattr(data, "content_type", "application/json"),
}
token = getattr(data, "token", None)
if token:
headers["Authorization"] = f"Bearer {token}"
return headers
# Trata os dados da respsota
async def _response(self, response: httpx.Response, data):
# Tenta JSON; se falhar, retorna texto bruto
try:
# Gerador de arquivo JSON
json_file_saver = JsonFileSaver()
# Obtem o código de requisição
status = response.status_code
# Converter o Json para objeto
response = DictToObj(response.json())
# Verifica o tipo de resposta
match status:
case 200:
rule("Dados enviados.:" + str(status))
ok("Verifique o log...")
json_file_saver.save(
response,
"storage/2XX/"
+ self.file_name_generator.generate("200")
+ ".json",
)
case 201:
rule("Dados criados.:" + str(status))
ok("Verifique o log...")
json_file_saver.save(
response,
"storage/2XX/"
+ self.file_name_generator.generate("201")
+ ".json",
)
case 400:
rule("Error.:" + str(status))
fail("Verifique o log...")
json_file_saver.save(
response,
"storage/4XX/"
+ self.file_name_generator.generate("400")
+ ".json",
)
case 404:
rule("Error.:" + str(status))
fail("Verifique o log...")
json_file_saver.save(
response,
"storage/4XX/"
+ self.file_name_generator.generate("404")
+ ".json",
)
case 422:
rule("Error.:" + str(status))
fail("Verifique o log....")
json_file_saver.save(
response,
"storage/4XX/"
+ self.file_name_generator.generate("422")
+ ".json",
)
return response
except ValueError:
return DictToObj(
{
"status": status,
"message": json.dumps(response, ensure_ascii=False, default=vars),
"data": None,
}
)
# Contrói a requisição
async def _request(self, client: httpx.AsyncClient, data):
"""
Constrói e envia a requisição com base no método HTTP definido em `data.method`.
Suporta:
- GET: usa params (query string)
- POST/PUT/PATCH: usa json ou form (data)
- DELETE: suporta params opcionais
"""
# Obtem o verbo de requisição
method = data.method.lower().strip()
# Obtem o endpoint
url = data.endpoint.lstrip("/")
# Prepara argumentos de envio
kwargs = {}
# Obtem o corpo da requisição
body = getattr(data, "body", None)
# Corpo JSON ou formulário (para POST/PUT/PATCH)
if body is not None:
# Sanitiza caracteres inválidos antes de enviar
body = self.sanitize_unicode(body)
# Guarda o corpo da requisição
kwargs["json"] = body
# Constrói o request (sem enviar ainda)
request = client.build_request(method.upper(), url, **kwargs)
# Envia a requisição (client.send respeita timeout e intercepta tudo)
response = await client.send(request)
# Se sucesso, trata normalmente
return await self._response(response, data)
# Prepara os dados para envio
async def send(self, data):
async with httpx.AsyncClient(
base_url=self.mirror_sync_env.api_url,
headers=self._headers(data),
timeout=getattr(data, "timeout", int(self.mirror_sync_env.timeout)),
follow_redirects=True,
) as client:
rule("Salvando Dados de Envio...")
if True:
json_file_saver = JsonFileSaver()
json_file_saver.save(
data,
"storage/data/" + self.file_name_generator.generate() + ".json",
)
response = await self._request(client, data)
# Pydantic v2 valida e ignora campos extras (ex.: userId)
return response