Source code for sagace.core.http_api_client
"""
--------------------------------------------------------------------------------------------------------------------
Descrição:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Este módulo fornece uma implementação concreta de um cliente HTTP autenticado dentro do sistema SAGACE.
A classe `HTTPAPIClient` herda de `APIClient`, garantindo que todas as requisições sejam autenticadas e sigam
um contrato unificado.
Principais funcionalidades:
- Realiza requisições HTTP autenticadas (GET, POST, PUT, DELETE).
- Gerencia o armazenamento e recuperação do token JWT.
- Lança exceções adequadas em caso de erro na API.
Classes:
- ``HTTPAPIClient``: Implementação concreta de `APIClient` utilizando `requests`.
Exemplo de uso:
.. code-block:: python
from sagace.infrastructure.http_api_client import HTTPAPIClient
from sagace.core import TokenStorage
api_client = HTTPAPIClient("https://api.sagace.online", TokenStorage())
response = api_client.get("/usuario/dados")
print(response)
Autor: Diego Yosiura
Última Atualização: 27/02/2025 16:30
Criado em: 27/02/2025 16:30
Copyright: (c) Ampere Consultoria Ltda
Projeto Original: sagace-v2-package
IDE: PyCharm
"""
import requests
from . import APIClient
from ..exceptions.domain import PermissionDeniedError, TokenExpiredError, APIRequestError
[docs]
class HTTPAPIClient(APIClient):
"""
Implementação concreta de `APIClient` utilizando `requests`.
Esta classe fornece uma implementação real para comunicação com APIs via HTTP,
garantindo que todas as requisições sejam autenticadas.
Princípios aplicados:
- **Liskov Substitution (L - SOLID)**: `HTTPAPIClient` pode ser utilizada no lugar de `APIClient` sem alterar o comportamento esperado.
- **Open/Closed (O - SOLID)**: A classe pode ser estendida para novos métodos HTTP sem modificação do código existente.
"""
[docs]
def request(self, method: str, endpoint: str, **kwargs):
"""
Método genérico para requisições HTTP autenticadas.
:param method: Método HTTP a ser utilizado (GET, POST, PUT, DELETE).
:type method: str
:param endpoint: Caminho relativo dentro da API.
:type endpoint: str
:param kwargs: Parâmetros adicionais para `requests.request()`.
:return: Resposta JSON da API.
:rtype: dict
:raises TokenExpiredError: Se o token estiver expirado.
:raises PermissionDeniedError: Se o usuário não tiver permissão para acessar o recurso.
:raises APIRequestError: Para quaisquer outros erros da API.
"""
# Constrói a URL completa garantindo que não haja barras duplicadas
url = f"{self.base_url}/{endpoint.lstrip('/')}"
headers = self._get_headers()
# Mescla headers passados como argumento com os padrões
if "headers" in kwargs:
kwargs["headers"].update(headers)
else:
kwargs["headers"] = headers
# Executa a requisição HTTP
response = requests.request(method, url, **kwargs)
# Tratamento de erros comuns da API
if response.status_code == 401:
raise TokenExpiredError()
elif response.status_code == 403:
raise PermissionDeniedError()
elif not response.ok:
raise APIRequestError(response.status_code, response.text)
return response.json()
[docs]
def get(self, endpoint: str, **kwargs):
"""
Método GET autenticado.
:param endpoint: Caminho relativo dentro da API.
:type endpoint: str
:param kwargs: Parâmetros adicionais para a requisição.
:return: Resposta JSON da API.
:rtype: dict
"""
return self.request("GET", endpoint, **kwargs)
[docs]
def post(self, endpoint: str, **kwargs):
"""
Método POST autenticado.
:param endpoint: Caminho relativo dentro da API.
:type endpoint: str
:param kwargs: Parâmetros adicionais para a requisição.
:return: Resposta JSON da API.
:rtype: dict
"""
return self.request("POST", endpoint, **kwargs)
[docs]
def put(self, endpoint: str, **kwargs):
"""
Método PUT autenticado.
:param endpoint: Caminho relativo dentro da API.
:type endpoint: str
:param kwargs: Parâmetros adicionais para a requisição.
:return: Resposta JSON da API.
:rtype: dict
"""
return self.request("PUT", endpoint, **kwargs)
[docs]
def delete(self, endpoint: str, **kwargs):
"""
Método DELETE autenticado.
:param endpoint: Caminho relativo dentro da API.
:type endpoint: str
:param kwargs: Parâmetros adicionais para a requisição.
:return: Resposta JSON da API.
:rtype: dict
"""
return self.request("DELETE", endpoint, **kwargs)