From 8c1763d42a28ed1db989471b4a026c43f56d9d06 Mon Sep 17 00:00:00 2001
From: Benoit Alessandroni <benoit@happy-dev.fr>
Date: Thu, 13 Oct 2022 16:30:04 +0200
Subject: [PATCH] update: adding swagger open-api template througr
 drf-spectacular for better documentation

---
 djangoldp/templates/swagger-ui.html | 31 +++++++++++++++++++++++++++++
 djangoldp/urls.py                   | 12 ++++++++++-
 djangoldp/views.py                  | 19 +++++++++++++++---
 setup.cfg                           |  1 +
 4 files changed, 59 insertions(+), 4 deletions(-)
 create mode 100644 djangoldp/templates/swagger-ui.html

diff --git a/djangoldp/templates/swagger-ui.html b/djangoldp/templates/swagger-ui.html
new file mode 100644
index 00000000..18456413
--- /dev/null
+++ b/djangoldp/templates/swagger-ui.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <title>Swagger</title>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@3/swagger-ui.css">
+</head>
+
+<body>
+    <div id="swagger-ui"></div>
+    <script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
+    <script>
+        const ui = SwaggerUIBundle({
+            url: "{% url 'schema' %}",
+            dom_id: '#swagger-ui',
+            presets: [
+                SwaggerUIBundle.presets.apis,
+                SwaggerUIBundle.SwaggerUIStandalonePreset
+            ],
+            layout: "BaseLayout",
+            requestInterceptor: (request) => {
+                request.headers['X-CSRFToken'] = "{{ csrf_token }}"
+                return request;
+            }
+        })
+    </script>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/djangoldp/urls.py b/djangoldp/urls.py
index 12d0e723..ed6a1648 100644
--- a/djangoldp/urls.py
+++ b/djangoldp/urls.py
@@ -2,12 +2,13 @@ from importlib import import_module
 
 from django.conf import settings
 from django.conf.urls import re_path, include
+from django.urls import path
 
 from djangoldp.models import LDPSource, Model
 from djangoldp.permissions import LDPPermissions
 from djangoldp.views import LDPSourceViewSet, WebFingerView, InboxView
 from djangoldp.views import LDPViewSet
-
+from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
 
 def __clean_path(path):
     '''ensures path is Django-friendly'''
@@ -41,6 +42,15 @@ urlpatterns = [
                                                                     permission_classes=[LDPPermissions], )),
     re_path(r'^\.well-known/webfinger/?$', WebFingerView.as_view()),
     re_path(r'^inbox/$', InboxView.as_view()),
+    path("schema/", SpectacularAPIView.as_view(), name="schema"),
+    path(
+        "docs/",
+        SpectacularSwaggerView.as_view(
+            template_name="swagger-ui.html", url_name="schema"
+        ),
+        name="swagger-ui",
+    ),
+    # re_path(r'^api-auth/', include("rest_framework.urls", namespace="rest_framework")),
 ]
 
 for package in settings.DJANGOLDP_PACKAGES:
diff --git a/djangoldp/views.py b/djangoldp/views.py
index 32316c64..a574ab4e 100644
--- a/djangoldp/views.py
+++ b/djangoldp/views.py
@@ -467,26 +467,39 @@ class LDPViewSet(LDPViewSetGenerator):
 
     def build_read_serializer(self):
         model_name = self.model._meta.object_name.lower()
-        lookup_field = get_resolver().reverse_dict[model_name + '-detail'][0][0][1][0]
+        try:
+            lookup_field = get_resolver().reverse_dict[model_name + '-detail'][0][0][1][0]
+        except:
+            lookup_field = 'urlid'
+            pass
+        
         meta_args = {'model': self.model, 'extra_kwargs': {
             '@id': {'lookup_field': lookup_field}},
                      'depth': getattr(self, 'depth', Model.get_meta(self.model, 'depth', 0)),
                      # 'depth': getattr(self, 'depth', 4),
                      'extra_fields': self.nested_fields}
+
         if self.fields:
             meta_args['fields'] = self.fields
         else:
             meta_args['exclude'] = Model.get_meta(self.model, 'serializer_fields_exclude') or ()
-        
+
         return self.build_serializer(meta_args, 'Read')
 
     def build_write_serializer(self):
         model_name = self.model._meta.object_name.lower()
-        lookup_field = get_resolver().reverse_dict[model_name + '-detail'][0][0][1][0]
+
+        try:
+            lookup_field = get_resolver().reverse_dict[model_name + '-detail'][0][0][1][0]
+        except:
+            lookup_field = 'urlid'
+            pass
+        
         meta_args = {'model': self.model, 'extra_kwargs': {
             '@id': {'lookup_field': lookup_field}},
                      'depth': 10,
                      'extra_fields': self.nested_fields}
+
         if self.fields:
             meta_args['fields'] = self.fields
         else:
diff --git a/setup.cfg b/setup.cfg
index 3dd375f7..30ec40cc 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -23,6 +23,7 @@ install_requires =
     django-guardian==2.3.0
     django-cookies-samesite~=0.8.0
     djangorestframework~=3.12
+    drf-spectacular~=0.24
     requests==2.23.0
     pyyaml==5.3.1
     pyyaml==5.3.1
-- 
GitLab