Repository: cookiecutter/cookiecutter-django

Issue:
Swagger UI Integration 
## Description

First of all, amazing template. Absolutely loved it. Would you be looking forward to integrate swagger support in this using https://drf-spectacular.readthedocs.io/en/latest/ ? 

I have already implemented it in a private fork of this project. Would like to contribute  it back if it's something that aligns with the project goals.

## Rationale

API Documentation is a very common requirement. Swagger is a great utility. The schema files generated by swagger can be directly imported into postman as well. Swagger integration in this project will be a huge value add.


Discussion:
Yes, adding API documentation would be a nice addition. I think we can do it whenever DRF is selected. Hopefully the integration isn't complicated and is not causing a lot of maintenance.
Yes, in my fork I am enabling it only when DRF is enabled. I have been using it for a while now and it's not complicated. I will create a PR for it on the weekend. :)

Resolving patch:
diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py
--- a/hooks/post_gen_project.py
+++ b/hooks/post_gen_project.py
@@ -327,6 +327,11 @@ def remove_drf_starter_files():
             "{{cookiecutter.project_slug}}", "users", "tests", "test_drf_views.py"
         )
     )
+    os.remove(
+        os.path.join(
+            "{{cookiecutter.project_slug}}", "users", "tests", "test_swagger_ui.py"
+        )
+    )
 
 
 def remove_storages_module():
diff --git a/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/config/settings/base.py
--- a/{{cookiecutter.project_slug}}/config/settings/base.py
+++ b/{{cookiecutter.project_slug}}/config/settings/base.py
@@ -84,6 +84,7 @@
     "rest_framework",
     "rest_framework.authtoken",
     "corsheaders",
+    "drf_spectacular",
 {%- endif %}
 ]
 
@@ -334,6 +335,18 @@
 # django-cors-headers - https://github.com/adamchainz/django-cors-headers#setup
 CORS_URLS_REGEX = r"^/api/.*$"
 
+# By Default swagger ui is available only to admin user. You can change permission classs to change that
+# See more configuration options at https://drf-spectacular.readthedocs.io/en/latest/settings.html#settings
+SPECTACULAR_SETTINGS = {
+    "TITLE": "{{ cookiecutter.project_name }} API",
+    "DESCRIPTION": "Documentation of API endpoiints of {{ cookiecutter.project_name }}",
+    "VERSION": "1.0.0",
+    "SERVE_PERMISSIONS": ["rest_framework.permissions.IsAdminUser"],
+    "SERVERS": [
+        {"url": "https://127.0.0.1:8000", "description": "Local Development server"},
+        {"url": "https://{{ cookiecutter.domain_name }}", "description": "Production server"},
+    ],
+}
 {%- endif %}
 # Your stuff...
 # ------------------------------------------------------------------------------
diff --git a/{{cookiecutter.project_slug}}/config/urls.py b/{{cookiecutter.project_slug}}/config/urls.py
--- a/{{cookiecutter.project_slug}}/config/urls.py
+++ b/{{cookiecutter.project_slug}}/config/urls.py
@@ -8,6 +8,7 @@
 from django.views import defaults as default_views
 from django.views.generic import TemplateView
 {%- if cookiecutter.use_drf == 'y' %}
+from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
 from rest_framework.authtoken.views import obtain_auth_token
 {%- endif %}
 
@@ -35,6 +36,12 @@
     path("api/", include("config.api_router")),
     # DRF auth token
     path("auth-token/", obtain_auth_token),
+    path("api/schema/", SpectacularAPIView.as_view(), name="api-schema"),
+    path(
+        "api/docs/",
+        SpectacularSwaggerView.as_view(url_name="api-schema"),
+        name="api-docs",
+    ),
 ]
 {%- endif %}
 


Test patch:
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_swagger_ui.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_swagger_ui.py
new file mode 100644
--- /dev/null
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/users/tests/test_swagger_ui.py
@@ -0,0 +1,16 @@
+import pytest
+from django.urls import reverse
+
+pytestmark = pytest.mark.django_db
+
+
+def test_swagger_accessible_by_admin(admin_client):
+    url = reverse("api-docs")
+    response = admin_client.get(url)
+    assert response.status_code == 200
+
+
+def test_swagger_ui_not_accessible_by_normal_user(client):
+    url = reverse("api-docs")
+    response = client.get(url)
+    assert response.status_code == 403