Python Quick Start
Get started with Bytedocs in Python applications
Bytedocs for Python supports popular frameworks with automatic Pydantic model detection and type hints analysis.
Supported Frameworks
- FastAPI - Modern, fast web framework with automatic API docs
- Flask - Micro web framework
- Django - Full-featured web framework
Installation
Choose your framework:
# FastAPI
pip install bytedocs-fastapi
# Flask
pip install bytedocs-flask
# Django
pip install bytedocs-django
Quick Start Examples
FastAPI
from fastapi import FastAPI
from bytedocs_fastapi import setup_bytedocs
# IMPORTANT: Disable FastAPI's built-in Swagger
app = FastAPI(
docs_url=None, # Disable default Swagger UI
redoc_url=None, # Disable default ReDoc
openapi_url=None # Disable default OpenAPI
)
# Setup Bytedocs - One line!
setup_bytedocs(app, {
"title": "My API",
"version": "1.0.0",
"description": "My awesome API"
})
# Define your routes as normal
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"id": user_id, "name": "John Doe"}
@app.post("/users")
async def create_user(name: str, email: str):
return {"id": 1, "name": name, "email": email}
FastAPI with Pydantic Models
from fastapi import FastAPI
from pydantic import BaseModel, Field, EmailStr
from bytedocs_fastapi import setup_bytedocs
app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
setup_bytedocs(app, {
"title": "My API",
"version": "1.0.0",
})
# Pydantic models are automatically documented
class User(BaseModel):
id: int = Field(..., description="User ID", example=123)
name: str = Field(..., description="User's full name", example="John Doe")
email: EmailStr = Field(..., description="Email address", example="john@example.com")
age: int | None = Field(None, ge=0, le=150, description="User's age")
class CreateUserRequest(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
email: EmailStr
age: int | None = Field(None, ge=0, le=150)
class UserResponse(BaseModel):
id: int
name: str
email: str
created_at: str
@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
return User(
id=user_id,
name="John Doe",
email="john@example.com",
age=30
)
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: CreateUserRequest):
return UserResponse(
id=1,
name=user.name,
email=user.email,
created_at="2025-01-01T00:00:00Z"
)
Flask
from flask import Flask, request, jsonify
from bytedocs_flask import setup_bytedocs
app = Flask(__name__)
# Setup Bytedocs
setup_bytedocs(app, {
"title": "My Flask API",
"version": "1.0.0",
})
@app.route('/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
"""
Get user by ID
---
parameters:
- name: user_id
in: path
type: integer
required: true
description: User ID
responses:
200:
description: User object
schema:
type: object
properties:
id:
type: integer
name:
type: string
email:
type: string
"""
return jsonify({
"id": user_id,
"name": "John Doe",
"email": "john@example.com"
})
@app.route('/users', methods=['POST'])
def create_user():
"""
Create a new user
---
parameters:
- name: body
in: body
required: true
schema:
type: object
required:
- name
- email
properties:
name:
type: string
email:
type: string
responses:
201:
description: Created user
"""
data = request.get_json()
return jsonify({
"id": 1,
"name": data['name'],
"email": data['email']
}), 201
if __name__ == '__main__':
app.run(debug=True)
Django
# settings.py
INSTALLED_APPS = [
# ...
'bytedocs_django',
]
BYTEDOCS = {
'TITLE': 'My Django API',
'VERSION': '1.0.0',
'DESCRIPTION': 'My awesome Django API',
'DOCS_PATH': '/docs',
}
# urls.py
from django.urls import path, include
from bytedocs_django import get_docs_urls
urlpatterns = [
# Your API endpoints
path('api/users/<int:user_id>/', views.get_user),
path('api/users/', views.create_user),
# Bytedocs
path('', include(get_docs_urls())),
]
# views.py
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
import json
@require_http_methods(["GET"])
def get_user(request, user_id):
"""
Get user by ID
"""
return JsonResponse({
"id": user_id,
"name": "John Doe",
"email": "john@example.com"
})
@require_http_methods(["POST"])
def create_user(request):
"""
Create a new user
"""
data = json.loads(request.body)
return JsonResponse({
"id": 1,
"name": data['name'],
"email": data['email']
}, status=201)
Configuration Options
Basic Configuration
setup_bytedocs(app, {
"title": "My API",
"version": "1.0.0",
"description": "API description",
"docs_path": "/docs", # Default: "/docs"
"auto_detect": True, # Default: True
})
Multiple Environments
setup_bytedocs(app, {
"title": "My API",
"version": "1.0.0",
"base_urls": [
{"name": "Production", "url": "https://api.example.com"},
{"name": "Staging", "url": "https://staging.example.com"},
{"name": "Local", "url": "http://localhost:8000"},
],
})
With Authentication
setup_bytedocs(app, {
"title": "My API",
"version": "1.0.0",
"auth": {
"enabled": True,
"type": "session",
"username": "admin",
"password": "secret",
},
})
With AI Assistant
import os
setup_bytedocs(app, {
"title": "My API",
"version": "1.0.0",
"ai": {
"enabled": True,
"provider": "openai",
"api_key": os.getenv("OPENAI_API_KEY"),
"model": "gpt-4o-mini",
},
})
Pydantic Model Detection
FastAPI's Pydantic models are automatically detected and documented:
Field Types
from pydantic import BaseModel
from typing import Optional, List
from datetime import datetime
class User(BaseModel):
# Basic types
id: int
name: str
email: str
active: bool
# Optional fields
age: Optional[int] = None
bio: Optional[str] = None
# Lists and nested types
tags: List[str] = []
roles: List[str] = ["user"]
# Dates
created_at: datetime
updated_at: Optional[datetime] = None
Field Validation
from pydantic import BaseModel, Field, validator
class CreateUserRequest(BaseModel):
name: str = Field(
...,
min_length=1,
max_length=100,
description="User's full name"
)
email: str = Field(
...,
regex=r'^[\w\.-]+@[\w\.-]+\.\w+$',
description="Valid email address"
)
age: int = Field(
...,
ge=0,
le=150,
description="User's age"
)
password: str = Field(
...,
min_length=8,
description="Password (min 8 characters)"
)
@validator('password')
def password_strength(cls, v):
if not any(char.isdigit() for char in v):
raise ValueError('Password must contain at least one digit')
return v
Field Examples
from pydantic import BaseModel, Field
class User(BaseModel):
id: int = Field(..., example=123)
name: str = Field(..., example="John Doe")
email: str = Field(..., example="john@example.com")
age: int = Field(None, example=30, ge=0, le=150)
Nested Models
from pydantic import BaseModel
from typing import List
class Address(BaseModel):
street: str
city: str
country: str
zipcode: str
class User(BaseModel):
id: int
name: str
email: str
address: Address # Nested model
addresses: List[Address] = [] # List of nested models
Type Hints
Python type hints are used for auto-detection:
Basic Type Hints
from typing import Optional, List, Dict
@app.get("/users/{user_id}")
async def get_user(
user_id: int, # Path parameter
include_posts: bool = False, # Query parameter
) -> Dict[str, any]: # Response type
return {"id": user_id, "name": "John"}
Advanced Type Hints
from typing import Union, Literal
@app.get("/search")
async def search(
query: str,
type: Literal["users", "posts", "comments"], # Enum
limit: int = 10,
offset: int = 0,
) -> Union[List[User], List[Post], List[Comment]]:
# Multiple return types
pass
FastAPI Dependencies
from fastapi import Depends, HTTPException, Header
from typing import Optional
async def get_current_user(
authorization: str = Header(..., description="Bearer token")
) -> User:
"""
Verify JWT token and return current user
"""
# Token verification logic
if not is_valid_token(authorization):
raise HTTPException(status_code=401, detail="Invalid token")
return get_user_from_token(authorization)
@app.get("/me", response_model=User)
async def get_my_profile(
current_user: User = Depends(get_current_user)
):
"""
Get current user's profile
Requires authentication
"""
return current_user
Response Models
Single Response
from pydantic import BaseModel
class UserResponse(BaseModel):
id: int
name: str
email: str
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
return UserResponse(
id=user_id,
name="John",
email="john@example.com"
)
Multiple Status Codes
from fastapi import HTTPException
from pydantic import BaseModel
class UserResponse(BaseModel):
id: int
name: str
class ErrorResponse(BaseModel):
detail: str
@app.get(
"/users/{user_id}",
response_model=UserResponse,
responses={
200: {"model": UserResponse, "description": "Success"},
404: {"model": ErrorResponse, "description": "User not found"},
}
)
async def get_user(user_id: int):
user = get_user_from_db(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
List Responses
from typing import List
@app.get("/users", response_model=List[UserResponse])
async def get_users(
limit: int = 10,
offset: int = 0
):
users = get_users_from_db(limit, offset)
return users
Paginated Responses
from pydantic import BaseModel
from typing import List, Generic, TypeVar
T = TypeVar('T')
class PaginatedResponse(BaseModel, Generic[T]):
items: List[T]
total: int
page: int
pages: int
@app.get("/users", response_model=PaginatedResponse[User])
async def get_users(page: int = 1, per_page: int = 10):
users, total = get_users_paginated(page, per_page)
return PaginatedResponse(
items=users,
total=total,
page=page,
pages=(total + per_page - 1) // per_page
)
Documentation Docstrings
FastAPI
@app.get("/users/{user_id}")
async def get_user(user_id: int):
"""
Get user by ID
Retrieve a specific user by their unique identifier.
Args:
user_id: The unique identifier of the user
Returns:
User object with all details
Raises:
404: User not found
"""
return get_user_from_db(user_id)
Flask (YAML format)
@app.route('/users/<int:user_id>')
def get_user(user_id):
"""
Get user by ID
---
tags:
- Users
parameters:
- name: user_id
in: path
type: integer
required: true
responses:
200:
description: User object
404:
description: User not found
"""
return jsonify(get_user_from_db(user_id))
Environment Variables
# .env file
BYTEDOCS_TITLE="My API"
BYTEDOCS_VERSION="1.0.0"
BYTEDOCS_DESCRIPTION="My awesome API"
BYTEDOCS_DOCS_PATH=/docs
BYTEDOCS_AUTO_DETECT=true
# Multiple environments
BYTEDOCS_PRODUCTION_URL=https://api.example.com
BYTEDOCS_STAGING_URL=https://staging.example.com
BYTEDOCS_LOCAL_URL=http://localhost:8000
# Authentication
BYTEDOCS_AUTH_ENABLED=true
BYTEDOCS_AUTH_TYPE=session
BYTEDOCS_AUTH_USERNAME=admin
BYTEDOCS_AUTH_PASSWORD=secret
# AI
BYTEDOCS_AI_ENABLED=true
BYTEDOCS_AI_PROVIDER=openai
BYTEDOCS_AI_API_KEY=sk-...
BYTEDOCS_AI_MODEL=gpt-4o-mini
Using in Configuration
import os
from dotenv import load_dotenv
load_dotenv()
setup_bytedocs(app, {
"title": os.getenv("BYTEDOCS_TITLE"),
"version": os.getenv("BYTEDOCS_VERSION"),
"description": os.getenv("BYTEDOCS_DESCRIPTION"),
"auth": {
"enabled": os.getenv("BYTEDOCS_AUTH_ENABLED") == "true",
"type": os.getenv("BYTEDOCS_AUTH_TYPE"),
"username": os.getenv("BYTEDOCS_AUTH_USERNAME"),
"password": os.getenv("BYTEDOCS_AUTH_PASSWORD"),
},
"ai": {
"enabled": os.getenv("BYTEDOCS_AI_ENABLED") == "true",
"provider": os.getenv("BYTEDOCS_AI_PROVIDER"),
"api_key": os.getenv("BYTEDOCS_AI_API_KEY"),
"model": os.getenv("BYTEDOCS_AI_MODEL"),
},
})
Production Deployment
Disable in Production
import os
if os.getenv("ENVIRONMENT") != "production":
setup_bytedocs(app, {
"title": "My API",
"version": "1.0.0",
})
Or Protect with Authentication
setup_bytedocs(app, {
"title": "My API",
"version": "1.0.0",
"auth": {
"enabled": os.getenv("ENVIRONMENT") == "production",
"type": "session",
"username": os.getenv("DOCS_USERNAME"),
"password": os.getenv("DOCS_PASSWORD"),
},
})
Best Practices
1. Use Pydantic Models (FastAPI)
# ✅ Good - Clear, auto-documented
class CreateUserRequest(BaseModel):
name: str
email: str
@app.post("/users")
async def create_user(user: CreateUserRequest):
pass
# ❌ Avoid - Unclear, manual documentation needed
@app.post("/users")
async def create_user(name: str, email: str):
pass
2. Add Response Models
# ✅ Good - Response schema documented
@app.get("/users/{id}", response_model=User)
async def get_user(id: int):
return get_user_from_db(id)
# ❌ Avoid - Response schema unknown
@app.get("/users/{id}")
async def get_user(id: int):
return get_user_from_db(id)
3. Use Type Hints
# ✅ Good - Types clear
async def get_user(user_id: int) -> User:
pass
# ❌ Avoid - Types unclear
async def get_user(user_id):
pass
4. Add Descriptions
# ✅ Good - Well documented
class User(BaseModel):
id: int = Field(..., description="Unique user identifier")
name: str = Field(..., description="Full name of the user")
email: str = Field(..., description="Email address (must be unique)")
# ❌ Avoid - No descriptions
class User(BaseModel):
id: int
name: str
email: str
Troubleshooting
Pydantic Models Not Detected
- Ensure response_model is set:
# ❌ Not detected
@app.get("/users/{id}")
async def get_user(id: int):
return user
# ✅ Detected
@app.get("/users/{id}", response_model=User)
async def get_user(id: int):
return user
FastAPI's Built-in Docs Conflict
# Disable FastAPI's built-in docs
app = FastAPI(
docs_url=None,
redoc_url=None,
openapi_url=None
)
Routes Not Appearing
Ensure Bytedocs is setup after routes are defined:
# Define routes first
@app.get("/users")
async def get_users():
pass
# Then setup Bytedocs
setup_bytedocs(app, config)
Visit Documentation
Start your server and visit:
http://localhost:8000/docs
What's Next?
- Core Concepts - Understand how Bytedocs works
- Configuration - Advanced configuration
- AI Assistant - Add intelligent chat
- Examples - Complete example projects
On this page