From 0def78d1a9fabe5277378b0f6321c463ee1e8017 Mon Sep 17 00:00:00 2001 From: rangelbruno Date: Thu, 5 Mar 2026 18:05:41 -0300 Subject: [PATCH] =?UTF-8?q?Feat(API):=20P=C3=A1gina=20interativa=20de=20do?= =?UTF-8?q?cumenta=C3=A7=C3=A3o=20e=20teste=20de=20endpoints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adiciona /api/doc/ com documentação auto-gerada de todos os endpoints REST, incluindo testador interativo com suporte a GET, POST, PUT, PATCH e DELETE, autenticação por token e busca por endpoints. --- sapl/api/urls.py | 6 +- sapl/api/views.py | 62 ++++ sapl/templates/api/api_doc.html | 514 ++++++++++++++++++++++++++++++++ 3 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 sapl/templates/api/api_doc.html diff --git a/sapl/api/urls.py b/sapl/api/urls.py index 1ab636707..01ae27fb3 100644 --- a/sapl/api/urls.py +++ b/sapl/api/urls.py @@ -4,7 +4,8 @@ from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView, \ from rest_framework.authtoken.views import obtain_auth_token from sapl.api.deprecated import SessaoPlenariaViewSet -from sapl.api.views import recria_token, SaplApiViewSetConstrutor +from sapl.api.views import recria_token, SaplApiViewSetConstrutor, \ + ApiDocView, api_doc_data from .apps import AppConfig from .views_health import HealthzView, ReadyzView @@ -33,6 +34,9 @@ urlpatterns_api_doc = [ ] urlpatterns = [ + url(r'^api/doc/$', ApiDocView.as_view(), name='api_doc'), + url(r'^api/doc/data/$', api_doc_data, name='api_doc_data'), + url(r'^api/', include(urlpatterns_api_doc)), url(r'^api/', include(urlpatterns_router)), diff --git a/sapl/api/views.py b/sapl/api/views.py index fac2eeeeb..d09faa1d0 100644 --- a/sapl/api/views.py +++ b/sapl/api/views.py @@ -2,6 +2,7 @@ import logging from django.conf import settings from django.http import HttpResponse, JsonResponse +from django.views.generic import TemplateView from rest_framework.authtoken.models import Token from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import IsAuthenticated, IsAdminUser @@ -22,6 +23,67 @@ def recria_token(request, pk): return Response({"message": "Token recriado com sucesso!", "token": token.key}) +class ApiDocView(TemplateView): + template_name = 'api/api_doc.html' + + +@api_view(['GET']) +@permission_classes([]) +def api_doc_data(request): + """Retorna metadados de todos os endpoints da API para a pagina de documentacao.""" + apps_data = {} + + for app_config, models_dict in ApiViewSetConstrutor._built_sets.items(): + app_label = app_config.label + models_data = {} + + for model, viewset_class in models_dict.items(): + model_name = model._meta.model_name + + # Determine allowed HTTP methods + allowed = getattr(viewset_class, 'http_method_names', + ['get', 'post', 'put', 'patch', 'delete', 'head', 'options']) + relevant_methods = {'get': 'GET', 'post': 'POST', 'put': 'PUT', + 'patch': 'PATCH', 'delete': 'DELETE'} + methods = [relevant_methods[m] for m in allowed if m in relevant_methods] + + # Discover custom @action endpoints + actions = [] + for attr_name in dir(viewset_class): + attr = getattr(viewset_class, attr_name, None) + if attr and hasattr(attr, 'mapping'): + url_path = getattr(attr, 'url_path', attr_name) + detail = getattr(attr, 'detail', False) + action_methods = [m.upper() for m in attr.mapping.keys() if m != ''] + if not action_methods: + action_methods = ['GET'] + + if detail: + action_url = f'{app_label}/{model_name}/{{pk}}/{url_path}/' + else: + action_url = f'{app_label}/{model_name}/{url_path}/' + + actions.append({ + 'name': attr_name, + 'url': action_url, + 'detail': detail, + 'methods': action_methods, + }) + + models_data[model_name] = { + 'url': f'{app_label}/{model_name}', + 'methods': methods, + 'verbose_name': str(model._meta.verbose_name), + 'verbose_name_plural': str(model._meta.verbose_name_plural), + 'actions': actions, + } + + if models_data: + apps_data[app_label] = models_data + + return Response({'apps': apps_data}) + + SaplApiViewSetConstrutor = ApiViewSetConstrutor SaplApiViewSetConstrutor.import_modules([ 'sapl.api.views_audiencia', diff --git a/sapl/templates/api/api_doc.html b/sapl/templates/api/api_doc.html new file mode 100644 index 000000000..d9e36376e --- /dev/null +++ b/sapl/templates/api/api_doc.html @@ -0,0 +1,514 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block head_title %}API - Documentacao{% endblock %} + +{% block base_content %} + + +
+
+

API REST - Documentacao

+
+ Swagger UI + ReDoc +
+
+ +
+
+
+
-
+ Apps +
+
+
+
+
-
+ Models +
+
+
+
+
-
+ Endpoints +
+
+
+ + +
+
Autenticacao
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+
+
+
+
+ +
+ + +
+ +
+ + +
+
+
+

Carregando endpoints...

+
+
+
+ + +{% endblock base_content %}