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_requireddecorators 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_requireddecorators on all views- Session-based token management
- Automatic redirect to admin login
- Protected schema endpoints
7. Styling Guidelines
Color Scheme:
- Primary:
#667eeato#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:
-
Color Scheme:
- Primary: Dark blue-gray (
#2c3e50) - Secondary: Bright blue (
#3498db) - Success: Green (
#27ae60) - Warning: Orange (
#f39c12) - Danger: Red (
#e74c3c)
- Primary: Dark blue-gray (
-
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
-
Typography:
- Primary font: 'Segoe UI' family for readability
- Monospace font for code elements
- Proper font weights and sizes for hierarchy
📱 Responsive Behavior:
-
Desktop (>768px):
- Fixed sidebar navigation
- Full-width main content
- Horizontal action buttons
-
Tablet (768px-480px):
- Collapsible sidebar with overlay
- Mobile toggle button
- Stacked action buttons
-
Mobile (<480px):
- Full-width content
- Compact spacing
- Horizontal scrolling for tables
🎯 Interactive Elements:
-
Sidebar Navigation:
- Collapsible app sections with smooth animations
- Hover effects with color transitions
- Active state indicators
- Chevron icons that rotate on expand/collapse
-
Endpoint Documentation:
- Smooth scrolling to sections
- Temporary highlight effect on navigation
- Tabbed response examples
- Syntax-highlighted JSON with Prism.js
-
Parameters Table:
- Hover effects on rows
- Color-coded parameter types
- Required/Optional badges
- Responsive table design
🔧 Functional Components:
-
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 */ -
JSON Response Viewer:
- Dark theme for better code readability
- Syntax highlighting with Prism.js
- Proper indentation and formatting
- Copy-friendly monospace font
-
Navigation Features:
- Smooth scroll behavior
- Active section highlighting
- Mobile-friendly touch targets
- Keyboard accessibility support
📋 Content Structure:
Each endpoint section includes:
-
Header Section:
- Endpoint name (large, bold)
- HTTP method badge
- URL path in code format
-
Description:
- Clear, readable explanation
- Proper line height and spacing
-
Parameters Table:
- Name (monospace, highlighted)
- Type (color-coded badge)
- Required/Optional status
- Description
-
Response Examples:
- Tabbed interface for different response types
- JSON syntax highlighting
- Dark theme for code readability
🎨 Animation & Transitions:
-
Smooth Transitions:
- 0.3s cubic-bezier easing for all elements
- Hover effects on interactive elements
- Smooth sidebar collapse/expand
-
Visual Feedback:
- Temporary highlight on section navigation
- Loading spinners for dynamic content
- Focus states for accessibility
-
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
- Create
apps/api/views/directory - Implement
documentation.pywith custom documentation view - Implement
swagger_views.pywith authentication views - Update
__init__.pyto export views
Step 2: Create Templates
- Create
templates/api/documentation.htmlwith responsive design - Create
templates/swagger/ui.htmlwith fixed header - Create
templates/swagger/auth.htmlfor token management - Ensure all templates are mobile-responsive
Step 3: Update URL Configuration
- Import required decorators and views
- Update schema_view configuration for admin-only access
- Create protected swagger_urlpatterns
- Add documentation routes to main urlpatterns
Step 4: Enhance Security
- Add
@staff_member_requireddecorators to all views - Update middleware for token handling
- Protect all documentation endpoints
- Test unauthorized access redirects
Step 5: Customize and Test
- Update API structure with your project's endpoints
- Customize branding and colors
- Test responsive design on different devices
- 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:
- Updating the project-specific details (names, URLs, branding)
- Customizing the API structure in the documentation view
- Adjusting the authentication system if needed
- Modifying the styling to match your project's design system