You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

44 KiB

Complete Prompt for Custom Swagger & API Documentation System Implementation

Overview

Implement a comprehensive custom API documentation system that replaces the default Swagger UI with a custom documentation interface, includes advanced authentication, and provides a beautiful user experience. The system should be restricted to admin users only.

Core Requirements

1. Custom API Documentation System

  • Create a custom API documentation view that overrides existing Swagger configuration
  • Implement a collapsible sidebar navigation where each Django app is displayed as a main item
  • When clicking on an app name, show/hide a list of API endpoints for that specific app underneath
  • When clicking on a specific endpoint, scroll to that section and display detailed API documentation including descriptions and response examples
  • Display response examples using a beautiful JSON editor/viewer with syntax highlighting
  • All content must be in English
  • The documentation should be responsive and work well on different screen sizes

2. Custom Swagger UI with Authentication

  • Override the existing Swagger setup with a custom implementation
  • Create a custom Swagger UI template with authentication banner
  • Implement token-based authentication system with 40-character Django tokens
  • Add session management for storing authentication tokens
  • Display user information and authentication status in a fixed header
  • Provide token management interface (login, logout, change token)

3. Security & Access Control

  • Restrict access to documentation, Swagger UI, and ReDoc to admin users only
  • Users must be logged into the Django admin panel to access any documentation
  • Implement @staff_member_required decorators on all documentation views
  • Update middleware to handle authentication for API endpoints
  • Redirect unauthorized users to admin login page

4. UI/UX Requirements

  • Fixed header in Swagger UI that stays visible during scrolling
  • Responsive design that works on mobile, tablet, and desktop
  • Beautiful gradient backgrounds and modern styling
  • Smooth animations and transitions
  • Professional color scheme and typography
  • Integration buttons between different documentation systems

Technical Implementation

File Structure to Create:

apps/api/views/
├── __init__.py
├── documentation.py
├── swagger_views.py
└── api_views.py

templates/
├── api/
│   └── documentation.html
├── swagger/
│   ├── ui.html
│   └── auth.html
└── admin/
    └── login_required.html

1. Custom Documentation View (apps/api/views/documentation.py)

import json
from django.shortcuts import render
from django.views import View
from django.contrib.admin.views.decorators import staff_member_required
from django.utils.decorators import method_decorator

@method_decorator(staff_member_required, name='dispatch')
class CustomAPIDocumentationView(View):
    """
    Custom API Documentation view with collapsible sidebar navigation
    Requires admin login to access
    """
    
    def get(self, request):
        api_structure = self._get_api_structure()
        context = {
            'api_structure': api_structure,
            'request': request,
            'title': 'Your Project API Documentation',
            'description': 'Comprehensive API documentation with interactive examples',
        }
        return render(request, 'api/documentation.html', context)
    
    def _get_api_structure(self):
        """
        Define your API structure here with apps, endpoints, parameters, and response examples
        """
        return {
            'app_name': {
                'name': 'App Display Name',
                'description': 'App description',
                'endpoints': [
                    {
                        'name': 'Endpoint Name',
                        'method': 'GET',
                        'url': '/api/endpoint/',
                        'description': 'Endpoint description',
                        'parameters': [
                            {'name': 'param', 'type': 'string', 'description': 'Parameter description', 'required': True}
                        ],
                        'response_examples': {
                            'success': json.dumps({"example": "response"}, indent=2)
                        }
                    }
                ]
            }
        }

2. Custom Swagger Views (apps/api/views/swagger_views.py)

from django.shortcuts import render, redirect
from django.views import View
from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required
from django.utils.decorators import method_decorator
from rest_framework.authtoken.models import Token

@method_decorator(staff_member_required, name='dispatch')
class CustomSwaggerView(View):
    """
    Custom Swagger UI view with authentication banner
    Requires admin login to access
    """
    def get(self, request):
        context = {
            'swagger_spec_url': '/en/swagger.json',  # Adjust based on your URL structure
            'request': request,
        }
        return render(request, 'swagger/ui.html', context)

@method_decorator(staff_member_required, name='dispatch')
class SwaggerTokenAuthView(View):
    """
    Token authentication management for Swagger
    """
    def get(self, request):
        context = {
            'current_token': request.session.get('swagger_token'),
            'user_info': request.session.get('swagger_user_info'),
        }
        return render(request, 'swagger/auth.html', context)
    
    def post(self, request):
        token = request.POST.get('token', '').strip()
        
        if not token or len(token) != 40:
            messages.error(request, 'Token must be exactly 40 characters long')
            return redirect('swagger-token-auth')
        
        try:
            token_obj = Token.objects.get(key=token)
            user = token_obj.user
            
            if not user.is_active:
                messages.error(request, 'User account is not active')
                return redirect('swagger-token-auth')
            
            request.session['swagger_token'] = token
            request.session['swagger_user_info'] = {
                'id': user.id,
                'email': user.email,
                'fullname': getattr(user, 'fullname', user.email),
                'is_staff': user.is_staff,
                'is_superuser': user.is_superuser,
                'user_type': 'User'
            }
            
            messages.success(request, f'Successfully authenticated as {user.email}')
            return redirect('schema-swagger-ui')
            
        except Token.DoesNotExist:
            messages.error(request, 'Invalid token')
            return redirect('swagger-token-auth')

@staff_member_required
def clear_swagger_auth(request):
    """Clear swagger authentication from session"""
    if 'swagger_token' in request.session:
        del request.session['swagger_token']
    if 'swagger_user_info' in request.session:
        del request.session['swagger_user_info']
    
    messages.success(request, 'Successfully logged out from Swagger')
    return redirect('swagger-token-auth')

3. Update URLs (config/urls.py)

from django.contrib.admin.views.decorators import staff_member_required
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from rest_framework import permissions
from apps.api.views import CustomAPIDocumentationView, CustomSwaggerView, SwaggerTokenAuthView, clear_swagger_auth

# Restricted schema view
schema_view = get_schema_view(
    openapi.Info(
        title="Your Project API",
        default_version='v1',
        description="Your Project API Documentation",
        contact=openapi.Contact(email="admin@yourproject.com"),
        license=openapi.License(name="Your License"),
    ),
    public=False,
    permission_classes=(permissions.IsAdminUser,),
)

# Protected swagger URL patterns
swagger_urlpatterns = [
    path('swagger-auth/', SwaggerTokenAuthView.as_view(), name='swagger-token-auth'),
    path('swagger-auth/clear/', clear_swagger_auth, name='clear-swagger-auth'),
    re_path(r'^swagger(?P<format>\.json|\.yaml)$',
            staff_member_required(schema_view.without_ui(cache_timeout=0)),
            name='schema-json'),
    path('swagger/', CustomSwaggerView.as_view(), name='schema-swagger-ui'),
    re_path(r'^redoc/$',
            staff_member_required(schema_view.with_ui('redoc', cache_timeout=0)),
            name='schema-redoc'),
]

urlpatterns += i18n_patterns(
    path("admin/", admin.site.urls),  # Adjust based on your admin setup
    path('docs/', CustomAPIDocumentationView.as_view(), name='docs-index'),
    *swagger_urlpatterns,
)

4. Enhanced Middleware (Update existing or create new)

from rest_framework.authtoken.models import Token
from django.contrib.auth import get_user_model

User = get_user_model()

def enhanced_auth_middleware(get_response):
    """
    Enhanced middleware for API authentication with admin restriction
    """
    def middleware(request):
        protected_paths = ["/swagger", "/redoc", "/docs"]
        is_protected_path = any(path in request.path for path in protected_paths)

        if is_protected_path:
            if request.user.is_authenticated and request.user.is_staff:
                # Provide API token for authenticated staff users
                if 'swagger_token' in request.session:
                    token = request.session['swagger_token']
                    request.META['HTTP_AUTHORIZATION'] = f"Token {token}"
                elif not request.META.get('HTTP_AUTHORIZATION'):
                    # Fallback to default admin user token
                    admin_user = User.objects.filter(is_staff=True).first()
                    if admin_user:
                        token, _ = Token.objects.get_or_create(user=admin_user)
                        request.META['HTTP_AUTHORIZATION'] = f"Token {token.key}"

        return get_response(request)

    return middleware

5. Templates

Custom Documentation Template (templates/api/documentation.html)

  • Responsive sidebar with collapsible app sections
  • Beautiful JSON viewer with Prism.js syntax highlighting
  • Smooth scrolling and animations
  • Links to Swagger UI and ReDoc
  • Mobile-friendly design

Custom Swagger UI Template (templates/swagger/ui.html)

  • Fixed header with authentication banner
  • User information display
  • Token management buttons
  • Links to custom documentation
  • Responsive design with proper mobile handling
  • Backdrop blur effects

Authentication Template (templates/swagger/auth.html)

  • Beautiful login form for token authentication
  • User information display
  • Token validation and management
  • Help section and instructions

6. Key Features to Implement

Fixed Header in Swagger UI:

.auth-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 9999;
    backdrop-filter: blur(10px);
}

body {
    padding-top: 80px; /* Adjust based on header height */
}

@media (max-width: 768px) {
    body {
        padding-top: 100px; /* More space for mobile */
    }
}

Responsive Design:

  • Mobile-first approach
  • Collapsible navigation
  • Touch-friendly buttons
  • Proper spacing and typography

Security Implementation:

  • @staff_member_required decorators on all views
  • Session-based token management
  • Automatic redirect to admin login
  • Protected schema endpoints

7. Styling Guidelines

Color Scheme:

  • Primary: #667eea to #764ba2 (gradient)
  • Success: #28a745
  • Warning: #f39c12
  • Danger: #e74c3c
  • Background: #f8f9fa

Typography:

  • Font Family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif
  • Responsive font sizes
  • Proper line heights and spacing

Components:

  • Rounded corners (6-12px border-radius)
  • Subtle shadows and gradients
  • Smooth transitions (0.3s ease)
  • Hover effects and animations

8. Integration Points

With Existing Admin:

  • Use existing admin authentication
  • Maintain admin session
  • Integrate with admin navigation if needed

With API System:

  • Discover endpoints automatically
  • Generate documentation from views
  • Include proper parameter documentation
  • Provide realistic response examples

9. Testing Checklist

  • Unauthorized users redirected to admin login
  • Authorized staff users can access all documentation
  • Fixed header works properly on all screen sizes
  • Token authentication system functions correctly
  • All links between documentation systems work
  • Mobile responsiveness is maintained
  • JSON syntax highlighting works
  • Collapsible navigation functions properly

10. Customization Notes

  • Replace "Your Project" with actual project name
  • Update API structure in _get_api_structure() method
  • Adjust URL patterns based on your project structure
  • Customize color scheme and branding
  • Add your specific API endpoints and documentation
  • Update contact information and licensing

Template Implementation Details

Custom Documentation Template Structure (templates/api/documentation.html)

This template should create a beautiful, responsive API documentation interface with the following structure and appearance:

Visual Layout:

┌─────────────────────────────────────────────────────────────┐
│                    Header with Title & Actions              │
├──────────────┬──────────────────────────────────────────────┤
│   Sidebar    │              Main Content                    │
│              │                                              │
│ ┌─ App 1     │  ┌─ Endpoint Documentation                   │
│ │ └─ GET /api │  │  Method + URL                            │
│ │ └─ POST /   │  │  Description                             │
│ │            │  │  Parameters Table                        │
│ ┌─ App 2     │  │  Response Examples (JSON)                │
│ │ └─ GET /    │  └─────────────────────────────────────────│
│ │ └─ PUT /    │                                              │
│              │  ┌─ Next Endpoint Documentation              │
│              │  │  ...                                      │
└──────────────┴──────────────────────────────────────────────┘

Complete Template Implementation:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }}</title>

    <!-- External Dependencies -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">

    <style>
        :root {
            --primary-color: #2c3e50;
            --secondary-color: #3498db;
            --success-color: #27ae60;
            --warning-color: #f39c12;
            --danger-color: #e74c3c;
            --light-bg: #f8f9fa;
            --dark-bg: #2c3e50;
            --sidebar-width: 300px;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: var(--light-bg);
            margin: 0;
            padding: 0;
        }

        /* Main Container */
        .documentation-container {
            display: flex;
            min-height: 100vh;
        }

        /* Sidebar Styles */
        .sidebar {
            width: var(--sidebar-width);
            background: linear-gradient(135deg, var(--dark-bg) 0%, #34495e 100%);
            color: white;
            position: fixed;
            height: 100vh;
            overflow-y: auto;
            z-index: 1000;
            box-shadow: 2px 0 10px rgba(0,0,0,0.1);
        }

        .sidebar-header {
            padding: 20px;
            background: rgba(0,0,0,0.2);
            border-bottom: 1px solid rgba(255,255,255,0.1);
        }

        .sidebar-header h3 {
            margin: 0;
            font-size: 1.2rem;
            font-weight: 600;
        }

        .sidebar-header p {
            margin: 5px 0 0 0;
            font-size: 0.9rem;
            opacity: 0.8;
        }

        /* App Navigation */
        .app-list {
            list-style: none;
            padding: 0;
            margin: 0;
        }

        .app-item {
            border-bottom: 1px solid rgba(255,255,255,0.1);
        }

        .app-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 15px 20px;
            cursor: pointer;
            transition: all 0.3s ease;
            background: transparent;
        }

        .app-header:hover {
            background: rgba(255,255,255,0.1);
        }

        .app-header.active {
            background: var(--secondary-color);
        }

        .app-name {
            font-weight: 600;
            font-size: 1rem;
        }

        .app-description {
            font-size: 0.8rem;
            opacity: 0.7;
            margin-top: 2px;
        }

        .toggle-icon {
            transition: transform 0.3s ease;
        }

        .toggle-icon.rotated {
            transform: rotate(90deg);
        }

        /* Endpoints List */
        .endpoints-list {
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.3s ease;
            background: rgba(0,0,0,0.2);
        }

        .endpoints-list.expanded {
            max-height: 500px;
        }

        .endpoint-item {
            padding: 10px 20px 10px 40px;
            cursor: pointer;
            transition: all 0.3s ease;
            border-left: 3px solid transparent;
        }

        .endpoint-item:hover {
            background: rgba(255,255,255,0.1);
            border-left-color: var(--success-color);
        }

        .endpoint-item.active {
            background: var(--success-color);
            border-left-color: white;
        }

        /* HTTP Method Badges */
        .endpoint-method {
            display: inline-block;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 0.7rem;
            font-weight: bold;
            margin-right: 8px;
        }

        .method-get { background: var(--success-color); }
        .method-post { background: var(--secondary-color); }
        .method-put { background: var(--warning-color); }
        .method-delete { background: var(--danger-color); }
        .method-patch { background: #9b59b6; }

        /* Main Content Area */
        .main-content {
            margin-left: var(--sidebar-width);
            flex: 1;
            padding: 30px;
            background: white;
        }

        /* Content Header */
        .content-header {
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 2px solid var(--light-bg);
        }

        .header-top {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }

        .content-header h1 {
            color: var(--dark-bg);
            margin-bottom: 10px;
            font-weight: 700;
        }

        .content-header p {
            color: #666;
            font-size: 1.1rem;
            margin: 0;
        }

        /* Action Buttons */
        .action-buttons {
            display: flex;
            gap: 10px;
        }

        .btn-swagger {
            background: #ff6b35;
            color: white;
            padding: 12px 20px;
            border-radius: 8px;
            text-decoration: none;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 8px;
            transition: all 0.3s ease;
        }

        .btn-swagger:hover {
            background: #e55a2b;
            color: white;
            text-decoration: none;
        }

        .btn-redoc {
            background: #39b982;
            color: white;
            padding: 12px 20px;
            border-radius: 8px;
            text-decoration: none;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 8px;
            transition: all 0.3s ease;
        }

        .btn-redoc:hover {
            background: #2d8f66;
            color: white;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <!-- Mobile Toggle Button -->
    <button class="mobile-toggle" onclick="toggleSidebar()">
        <i class="fas fa-bars"></i>
    </button>

    <div class="documentation-container">
        <!-- Sidebar Navigation -->
        <div class="sidebar" id="sidebar">
            <div class="sidebar-header">
                <h3><i class="fas fa-book"></i> API Documentation</h3>
                <p>{{ description }}</p>
            </div>

            <ul class="app-list">
                {% for app_key, app_data in api_structure.items %}
                <li class="app-item">
                    <div class="app-header" onclick="toggleEndpoints('{{ app_key }}-endpoints')">
                        <div>
                            <div class="app-name">{{ app_data.name }}</div>
                            <div class="app-description">{{ app_data.description }}</div>
                        </div>
                        <i class="fas fa-chevron-right toggle-icon" id="{{ app_key }}-icon"></i>
                    </div>

                    <ul class="endpoints-list" id="{{ app_key }}-endpoints">
                        {% for endpoint in app_data.endpoints %}
                        <li class="endpoint-item" onclick="scrollToEndpoint('{{ app_key }}-{{ forloop.counter0 }}')">
                            <span class="endpoint-method method-{{ endpoint.method|lower }}">{{ endpoint.method }}</span>
                            {{ endpoint.name }}
                        </li>
                        {% endfor %}
                    </ul>
                </li>
                {% endfor %}
            </ul>
        </div>

        <!-- Main Content -->
        <div class="main-content">
            <div class="content-header">
                <div class="header-top">
                    <div>
                        <h1>{{ title }}</h1>
                        <p>{{ description }}</p>
                    </div>
                    <div class="action-buttons">
                        <a href="{% url 'schema-swagger-ui' %}" class="btn-swagger">
                            <i class="fas fa-code"></i>
                            Swagger UI
                        </a>
                        <a href="{% url 'schema-redoc' %}" class="btn-redoc">
                            <i class="fas fa-book"></i>
                            ReDoc
                        </a>
                    </div>
                </div>
            </div>

            <!-- API Endpoints Documentation -->
            {% for app_key, app_data in api_structure.items %}
                {% for endpoint in app_data.endpoints %}
                <div class="endpoint-section" id="{{ app_key }}-{{ forloop.counter0 }}">
                    <div class="endpoint-header">
                        <h2 class="endpoint-title">{{ endpoint.name }}</h2>
                        <span class="endpoint-method method-{{ endpoint.method|lower }}">{{ endpoint.method }}</span>
                        <code class="endpoint-url">{{ endpoint.url }}</code>
                    </div>

                    <p class="endpoint-description">{{ endpoint.description }}</p>

                    {% if endpoint.parameters %}
                    <div class="parameters-section">
                        <h3 class="section-title">
                            <i class="fas fa-cogs"></i>
                            Parameters
                        </h3>
                        <table class="parameters-table">
                            <thead>
                                <tr>
                                    <th>Name</th>
                                    <th>Type</th>
                                    <th>Required</th>
                                    <th>Description</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for param in endpoint.parameters %}
                                <tr>
                                    <td><code class="param-name">{{ param.name }}</code></td>
                                    <td><span class="param-type">{{ param.type }}</span></td>
                                    <td>
                                        {% if param.required %}
                                            <span class="param-required">Required</span>
                                        {% else %}
                                            <span class="param-type">Optional</span>
                                        {% endif %}
                                    </td>
                                    <td>{{ param.description }}</td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                    {% endif %}

                    <div class="response-section">
                        <h3 class="section-title">
                            <i class="fas fa-code"></i>
                            Response Examples
                        </h3>

                        <div class="response-tabs">
                            {% for response_type, response_data in endpoint.response_examples.items %}
                            <button class="response-tab {% if forloop.first %}active{% endif %}"
                                    onclick="showResponse('{{ app_key }}-{{ forloop.parentloop.counter0 }}', '{{ response_type }}')">
                                {{ response_type|title }} Response
                            </button>
                            {% endfor %}
                        </div>

                        {% for response_type, response_data in endpoint.response_examples.items %}
                        <div class="json-viewer" id="{{ app_key }}-{{ forloop.parentloop.counter0 }}-{{ response_type }}"
                             style="{% if not forloop.first %}display: none;{% endif %}">
                            <pre><code class="language-json">{{ response_data|safe }}</code></pre>
                        </div>
                        {% endfor %}
                    </div>
                </div>
                {% endfor %}
            {% endfor %}
        </div>
    </div>

    <!-- JavaScript for Functionality -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>

    <script>
        // Toggle sidebar for mobile
        function toggleSidebar() {
            const sidebar = document.getElementById('sidebar');
            sidebar.classList.toggle('mobile-open');
        }

        // Toggle endpoints list
        function toggleEndpoints(endpointsId) {
            const endpointsList = document.getElementById(endpointsId);
            const icon = document.getElementById(endpointsId.replace('-endpoints', '-icon'));
            const header = icon.closest('.app-header');

            endpointsList.classList.toggle('expanded');
            icon.classList.toggle('rotated');
            header.classList.toggle('active');
        }

        // Scroll to endpoint section
        function scrollToEndpoint(endpointId) {
            const element = document.getElementById(endpointId);
            if (element) {
                element.scrollIntoView({
                    behavior: 'smooth',
                    block: 'start'
                });

                // Highlight the endpoint temporarily
                element.style.boxShadow = '0 0 20px rgba(52, 152, 219, 0.3)';
                setTimeout(() => {
                    element.style.boxShadow = '0 4px 20px rgba(0,0,0,0.08)';
                }, 2000);
            }

            // Close sidebar on mobile after selection
            if (window.innerWidth <= 768) {
                document.getElementById('sidebar').classList.remove('mobile-open');
            }
        }

        // Show response example
        function showResponse(endpointId, responseType) {
            // Hide all response examples for this endpoint
            const allResponses = document.querySelectorAll(`[id^="${endpointId}-"]`);
            allResponses.forEach(response => {
                if (response.classList.contains('json-viewer')) {
                    response.style.display = 'none';
                }
            });

            // Show selected response
            const selectedResponse = document.getElementById(`${endpointId}-${responseType}`);
            if (selectedResponse) {
                selectedResponse.style.display = 'block';
            }

            // Update tab active state
            const tabs = document.querySelectorAll('.response-tab');
            tabs.forEach(tab => tab.classList.remove('active'));
            event.target.classList.add('active');
        }

        // Format JSON in response examples
        document.addEventListener('DOMContentLoaded', function() {
            const jsonViewers = document.querySelectorAll('.json-viewer pre code');
            jsonViewers.forEach(viewer => {
                try {
                    const jsonText = viewer.textContent;
                    const jsonObj = JSON.parse(jsonText);
                    const formattedJson = JSON.stringify(jsonObj, null, 2);
                    viewer.textContent = formattedJson;
                } catch (e) {
                    // If it's not valid JSON, leave it as is
                    console.log('Not valid JSON:', e);
                }
            });

            // Initialize Prism.js for syntax highlighting
            if (typeof Prism !== 'undefined') {
                Prism.highlightAll();
            }
        });

        // Close sidebar when clicking outside on mobile
        document.addEventListener('click', function(event) {
            if (window.innerWidth <= 768) {
                const sidebar = document.getElementById('sidebar');
                const mobileToggle = document.querySelector('.mobile-toggle');

                if (!sidebar.contains(event.target) && !mobileToggle.contains(event.target)) {
                    sidebar.classList.remove('mobile-open');
                }
            }
        });
    </script>
</body>
</html>

Additional CSS Styles for Complete Functionality

Add these styles to complete the documentation template:

/* Endpoint Documentation Styles */
.endpoint-section {
    margin-bottom: 40px;
    padding: 25px;
    background: white;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0,0,0,0.08);
    border: 1px solid #e9ecef;
}

.endpoint-header {
    display: flex;
    align-items: center;
    margin-bottom: 20px;
    padding-bottom: 15px;
    border-bottom: 1px solid #e9ecef;
    flex-wrap: wrap;
    gap: 15px;
}

.endpoint-title {
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--dark-bg);
    margin: 0;
}

.endpoint-url {
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    background: var(--light-bg);
    padding: 8px 12px;
    border-radius: 6px;
    font-size: 0.9rem;
    color: var(--dark-bg);
    border: 1px solid #dee2e6;
}

.endpoint-description {
    color: #666;
    margin-bottom: 25px;
    line-height: 1.6;
    font-size: 1rem;
}

/* Parameters Section */
.parameters-section {
    margin-bottom: 25px;
}

.section-title {
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--dark-bg);
    margin-bottom: 15px;
    display: flex;
    align-items: center;
}

.section-title i {
    margin-right: 8px;
    color: var(--secondary-color);
}

.parameters-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 20px;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}

.parameters-table th,
.parameters-table td {
    padding: 12px 15px;
    text-align: left;
    border-bottom: 1px solid #e9ecef;
}

.parameters-table th {
    background: var(--light-bg);
    font-weight: 600;
    color: var(--dark-bg);
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.parameters-table tbody tr:hover {
    background: #f8f9fa;
}

.param-name {
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    font-weight: 600;
    color: var(--secondary-color);
    background: #f8f9fa;
    padding: 4px 8px;
    border-radius: 4px;
}

.param-type {
    background: #e3f2fd;
    color: #1976d2;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 0.8rem;
    font-weight: 500;
    text-transform: uppercase;
}

.param-required {
    background: #ffebee;
    color: #c62828;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 0.8rem;
    font-weight: 500;
    text-transform: uppercase;
}

/* Response Examples Section */
.response-section {
    margin-top: 25px;
}

.response-tabs {
    display: flex;
    margin-bottom: 15px;
    border-bottom: 1px solid #e9ecef;
    gap: 5px;
}

.response-tab {
    padding: 10px 20px;
    cursor: pointer;
    border: none;
    background: none;
    color: #666;
    font-weight: 500;
    transition: all 0.3s ease;
    border-radius: 6px 6px 0 0;
    position: relative;
}

.response-tab:hover {
    background: #f8f9fa;
    color: var(--secondary-color);
}

.response-tab.active {
    color: var(--secondary-color);
    background: #f8f9fa;
    border-bottom: 2px solid var(--secondary-color);
}

.json-viewer {
    background: #1e1e1e;
    border-radius: 8px;
    padding: 20px;
    margin-top: 15px;
    overflow-x: auto;
    border: 1px solid #e9ecef;
}

.json-viewer pre {
    margin: 0;
    color: #d4d4d4;
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    font-size: 0.9rem;
    line-height: 1.5;
}

/* Mobile Responsive Design */
.mobile-toggle {
    display: none;
    position: fixed;
    top: 20px;
    left: 20px;
    z-index: 1001;
    background: var(--secondary-color);
    color: white;
    border: none;
    padding: 10px;
    border-radius: 6px;
    cursor: pointer;
    box-shadow: 0 2px 10px rgba(0,0,0,0.2);
}

@media (max-width: 768px) {
    .mobile-toggle {
        display: block;
    }

    .sidebar {
        transform: translateX(-100%);
        transition: transform 0.3s ease;
    }

    .sidebar.mobile-open {
        transform: translateX(0);
    }

    .main-content {
        margin-left: 0;
        padding: 20px 15px;
    }

    .endpoint-header {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
    }

    .action-buttons {
        flex-direction: column;
        width: 100%;
    }

    .btn-swagger,
    .btn-redoc {
        justify-content: center;
        width: 100%;
    }

    .parameters-table {
        font-size: 0.8rem;
    }

    .parameters-table th,
    .parameters-table td {
        padding: 8px 10px;
    }

    .response-tabs {
        flex-wrap: wrap;
    }

    .response-tab {
        padding: 8px 15px;
        font-size: 0.9rem;
    }
}

@media (max-width: 480px) {
    .main-content {
        padding: 15px 10px;
    }

    .endpoint-section {
        padding: 15px;
    }

    .endpoint-title {
        font-size: 1.2rem;
    }

    .parameters-table {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
    }
}

/* Scrollbar Styling */
.sidebar::-webkit-scrollbar {
    width: 6px;
}

.sidebar::-webkit-scrollbar-track {
    background: rgba(255,255,255,0.1);
}

.sidebar::-webkit-scrollbar-thumb {
    background: rgba(255,255,255,0.3);
    border-radius: 3px;
}

.sidebar::-webkit-scrollbar-thumb:hover {
    background: rgba(255,255,255,0.5);
}

/* Loading Animation */
.loading {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 40px;
}

.spinner {
    width: 40px;
    height: 40px;
    border: 4px solid #f3f3f3;
    border-top: 4px solid var(--secondary-color);
    border-radius: 50%;
    animation: spin 1s linear infinite;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

/* Smooth Animations */
* {
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Focus States for Accessibility */
.endpoint-item:focus,
.app-header:focus,
.response-tab:focus {
    outline: 2px solid var(--secondary-color);
    outline-offset: 2px;
}

Template Features & Appearance:

🎨 Visual Design Elements:
  1. Color Scheme:

    • Primary: Dark blue-gray (#2c3e50)
    • Secondary: Bright blue (#3498db)
    • Success: Green (#27ae60)
    • Warning: Orange (#f39c12)
    • Danger: Red (#e74c3c)
  2. Layout Structure:

    • Fixed sidebar (300px width) with dark gradient background
    • Main content area with white background and proper spacing
    • Responsive design that collapses sidebar on mobile
  3. Typography:

    • Primary font: 'Segoe UI' family for readability
    • Monospace font for code elements
    • Proper font weights and sizes for hierarchy
📱 Responsive Behavior:
  1. Desktop (>768px):

    • Fixed sidebar navigation
    • Full-width main content
    • Horizontal action buttons
  2. Tablet (768px-480px):

    • Collapsible sidebar with overlay
    • Mobile toggle button
    • Stacked action buttons
  3. Mobile (<480px):

    • Full-width content
    • Compact spacing
    • Horizontal scrolling for tables
🎯 Interactive Elements:
  1. Sidebar Navigation:

    • Collapsible app sections with smooth animations
    • Hover effects with color transitions
    • Active state indicators
    • Chevron icons that rotate on expand/collapse
  2. Endpoint Documentation:

    • Smooth scrolling to sections
    • Temporary highlight effect on navigation
    • Tabbed response examples
    • Syntax-highlighted JSON with Prism.js
  3. Parameters Table:

    • Hover effects on rows
    • Color-coded parameter types
    • Required/Optional badges
    • Responsive table design
🔧 Functional Components:
  1. HTTP Method Badges:

    .method-get { background: #27ae60; }    /* Green */
    .method-post { background: #3498db; }   /* Blue */
    .method-put { background: #f39c12; }    /* Orange */
    .method-delete { background: #e74c3c; } /* Red */
    .method-patch { background: #9b59b6; }  /* Purple */
    
  2. JSON Response Viewer:

    • Dark theme for better code readability
    • Syntax highlighting with Prism.js
    • Proper indentation and formatting
    • Copy-friendly monospace font
  3. Navigation Features:

    • Smooth scroll behavior
    • Active section highlighting
    • Mobile-friendly touch targets
    • Keyboard accessibility support
📋 Content Structure:

Each endpoint section includes:

  1. Header Section:

    • Endpoint name (large, bold)
    • HTTP method badge
    • URL path in code format
  2. Description:

    • Clear, readable explanation
    • Proper line height and spacing
  3. Parameters Table:

    • Name (monospace, highlighted)
    • Type (color-coded badge)
    • Required/Optional status
    • Description
  4. Response Examples:

    • Tabbed interface for different response types
    • JSON syntax highlighting
    • Dark theme for code readability
🎨 Animation & Transitions:
  1. Smooth Transitions:

    • 0.3s cubic-bezier easing for all elements
    • Hover effects on interactive elements
    • Smooth sidebar collapse/expand
  2. Visual Feedback:

    • Temporary highlight on section navigation
    • Loading spinners for dynamic content
    • Focus states for accessibility
  3. Mobile Interactions:

    • Touch-friendly button sizes
    • Swipe-friendly sidebar overlay
    • Responsive touch targets

This template creates a professional, modern API documentation interface that rivals commercial documentation platforms while maintaining full customization control and integration with your Django project.

Custom Swagger UI Template Structure

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Swagger UI CSS and custom styles -->
    <link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui.css" />
    <style>
        /* Fixed header styles */
        .auth-banner {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            z-index: 9999;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            /* Additional styling */
        }

        body {
            padding-top: 80px;
        }

        /* Responsive adjustments */
        @media (max-width: 768px) {
            body { padding-top: 100px; }
        }
    </style>
</head>
<body>
    <!-- Fixed authentication banner -->
    <div class="auth-banner">
        <!-- User info and action buttons -->
    </div>

    <!-- Swagger UI container -->
    <div id="swagger-ui"></div>

    <!-- Swagger UI JavaScript with token injection -->
    <script>
        SwaggerUIBundle({
            url: '{{ swagger_spec_url }}',
            requestInterceptor: function(request) {
                // Add authorization header
                request.headers['Authorization'] = 'Token {{ request.session.swagger_token }}';
                return request;
            }
        });
    </script>
</body>
</html>

Implementation Steps

Step 1: Create View Structure

  1. Create apps/api/views/ directory
  2. Implement documentation.py with custom documentation view
  3. Implement swagger_views.py with authentication views
  4. Update __init__.py to export views

Step 2: Create Templates

  1. Create templates/api/documentation.html with responsive design
  2. Create templates/swagger/ui.html with fixed header
  3. Create templates/swagger/auth.html for token management
  4. Ensure all templates are mobile-responsive

Step 3: Update URL Configuration

  1. Import required decorators and views
  2. Update schema_view configuration for admin-only access
  3. Create protected swagger_urlpatterns
  4. Add documentation routes to main urlpatterns

Step 4: Enhance Security

  1. Add @staff_member_required decorators to all views
  2. Update middleware for token handling
  3. Protect all documentation endpoints
  4. Test unauthorized access redirects

Step 5: Customize and Test

  1. Update API structure with your project's endpoints
  2. Customize branding and colors
  3. Test responsive design on different devices
  4. Verify authentication flow works correctly

Final Notes

This implementation provides:

  • Complete security: Only admin users can access documentation
  • Beautiful UI: Modern, responsive design with smooth animations
  • Token management: Full authentication system for API testing
  • Integration: Seamless connection between different documentation systems
  • Customizable: Easy to adapt for any Django project

The system maintains the professional look while providing all the functionality needed for comprehensive API documentation and testing.

This implementation can be adapted to any Django project by:

  1. Updating the project-specific details (names, URLs, branding)
  2. Customizing the API structure in the documentation view
  3. Adjusting the authentication system if needed
  4. Modifying the styling to match your project's design system