Add API Docummentation

This commit is contained in:
Eduardo Silva
2026-02-11 16:49:32 -03:00
parent 8c6a5262d3
commit 1dcf94518f
5 changed files with 128 additions and 2 deletions

View File

@@ -1,9 +1,10 @@
from django.urls import path
from api_v2.views import view_api_key_list, view_manage_api_key, view_delete_api_key
from api_v2.views import view_api_key_list, view_manage_api_key, view_delete_api_key, view_api_docs
urlpatterns = [
path('list/', view_api_key_list, name='api_v2_list'),
path('manage/', view_manage_api_key, name='api_v2_manage'),
path('delete/<uuid:uuid>/', view_delete_api_key, name='api_v2_delete'),
path('docs/', view_api_docs, name='api_v2_docs'),
]

View File

@@ -94,3 +94,32 @@ def view_delete_api_key(request, uuid):
'text': _('Are you sure you want to delete the API Key "%(name)s"?') % {'name': api_key.name}
}
return render(request, 'generic_delete_confirmation.html', context)
@login_required
def view_api_docs(request):
from django.urls.resolvers import URLPattern
from api_v2 import urls_api
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
docs = []
# We iterate over the urlpatterns from the api_v2.urls_api module
for pattern in urls_api.urlpatterns:
if isinstance(pattern, URLPattern):
view_func = pattern.callback
# The view might be wrapped (e.g. by @csrf_exempt), but @api_doc metadata
# should have been preserved on the wrapper or be available on the original function.
# verify_api_doc checks handled this.
if hasattr(view_func, 'api_doc'):
doc_data = view_func.api_doc.copy()
doc_data['url_pattern'] = str(pattern.pattern)
doc_data['name'] = pattern.name
docs.append(doc_data)
context = {
'page_title': _('API Documentation'),
'docs': docs
}
return render(request, 'api_v2/api_documentation.html', context)

View File

@@ -15,13 +15,14 @@ from wireguard_tools.views import export_wireguard_configuration
from .models import ApiKey
def api_doc(*, summary: str, auth: str, params: list, returns: list, examples: Optional[dict] = None):
def api_doc(*, summary: str, auth: str, params: list, returns: list, methods: Optional[List[str]] = None, examples: Optional[dict] = None):
def decorator(view_func):
view_func.api_doc = {
"summary": summary,
"auth": auth,
"params": params,
"returns": returns,
"methods": methods or ["POST"],
"examples": examples or {},
}
@@ -166,6 +167,7 @@ def _get_wireguard_instance(instance_name: str) -> Optional[WireGuardInstance]:
@api_doc(
summary="Create / Update / Delete a WireGuard peer (and optionally reload the interface)",
auth="Header token: <ApiKey.token>",
methods=["POST", "PUT", "DELETE"],
params=[
{"name": "instance", "in": "json", "type": "string", "required": True, "example": "wg0",
"description": "Target instance name in the format wg{instance_id} (e.g. wg0, wg1)."},
@@ -450,6 +452,7 @@ def api_v2_manage_peer(request):
@api_doc(
summary="List peers for a specific instance (required)",
auth="Header token: <ApiKey.token>",
methods=["POST", "GET"],
params=[
{"name": "instance", "in": "json", "type": "string", "required": True, "example": "wg2",
"description": "Required. Target instance name in the format wg{instance_id} (e.g. wg0, wg1)."},
@@ -523,6 +526,7 @@ def api_v2_peer_list(request):
@api_doc(
summary="Peer details for a specific instance (required) by peer_uuid or peer_public_key",
auth="Header token: <ApiKey.token>",
methods=["POST", "GET"],
params=[
{"name": "instance", "in": "json", "type": "string", "required": True, "example": "wg2",
"description": "Required. Target instance name in the format wg{instance_id} (e.g. wg0, wg1)."},