This document outlines the architecture plan for a robust, professional API Documentation Generator. The goal is to create a system capable of generating comprehensive, easy-to-understand, and maintainable API documentation, including endpoint descriptions, request/response examples, authentication guides, and SDK usage examples.
The primary objective of the API Documentation Generator is to automate the creation of high-quality, interactive, and consistent API documentation. This system will ingest API definitions from various sources, process them, and render them into multiple output formats suitable for developers, technical writers, and product managers. By standardizing documentation generation, we aim to improve developer experience, reduce manual effort, and ensure accuracy across all API versions.
The system will follow a modular, pipeline-based architecture, allowing for flexible input sources, processing steps, and output formats.
+-------------------+ +-------------------+ +-------------------------+ +-------------------+
| Input Sources | --> | Parser & | --> | Intermediate Data Model | --> | Template Engine / |
| (OpenAPI, Postman,| | Validation | | (Standardized IR) | | Renderer |
| Code Annotations) | | | | | | |
+-------------------+ +-------------------+ +-------------------------+ +-------------------+
| |
| V
+--------------------------------------------------------------------------------------+-------------------+
| Output Formats |
| (HTML, Markdown, |
| PDF, Postman Coll)|
+-------------------+
The API Documentation Generator can be deployed in several ways:
This roadmap outlines the key phases for developing the API Documentation Generator itself.
* Week 1: Set up project structure, choose core tech stack (e.g., Python + Jinja2). Implement basic OpenAPI 3.x parser to IR.
* Week 2: Develop the Intermediate Data Model (IR) for API info, paths, parameters, and responses. Implement IR validation.
* Week 3: Create a basic Jinja2 templating system. Implement a default HTML template for displaying endpoints, parameters, and responses.
* Week 4: Implement Markdown output generation. Develop a CLI for basic generate command.
* Week 5: Implement automatic request/response example generation based on schemas. Allow for custom example injection.
* Week 6: Integrate security scheme parsing into IR. Develop a template for common authentication guides (API Key, Bearer Token).
* Week 7: Implement SDK usage example generation (e.g., cURL, Python requests).
* Week 8: Refine default HTML/Markdown templates for better readability, navigation, and search functionality.
* Week 9: Implement Postman Collection v2.x parser to IR.
* Week 10: Add support for OpenAPI 2.0 (Swagger) specification.
* Week 11: Implement PDF output generation using HTML-to-PDF conversion.
* Week 12: Develop a Postman Collection exporter from the IR. Enhance CLI with configuration options (input path, output directory, template selection).
* Week 13: Create Dockerfile for the generator.
* Week 14: Develop basic CI/CD pipeline examples (e.g., GitHub Actions) to automatically generate docs on push/release.
* Week 15: Implement a versioning strategy for documentation (
This deliverable provides comprehensive, detailed, and production-ready Python code designed to serve as the core engine for generating professional API documentation. This code focuses on defining API structures, generating example data, and rendering the documentation into a human-readable format (Markdown in this example), while also providing a framework for SDK usage examples.
The goal of this code is to provide a robust, extensible foundation for automating API documentation generation. By separating API definition (data models) from rendering logic, we ensure maintainability, consistency, and the ability to output to various formats (Markdown, HTML, OpenAPI YAML, etc.) by simply swapping out renderers.
Key Design Principles:
The generated code is structured into the following logical components:
api_models.py)This section defines the Pydantic models that represent the structure of your API. These models serve as the single source of truth for your API definition, enabling consistent documentation generation.
# api_models.py
from pydantic import BaseModel, Field
from typing import Dict, List, Literal, Any, Optional
class Parameter(BaseModel):
"""
Represents a single API endpoint parameter.
"""
name: str = Field(..., description="The name of the parameter.")
type: Literal["string", "integer", "boolean", "object", "array"] = Field(
..., description="The data type of the parameter."
)
location: Literal["query", "header", "path", "body", "cookie"] = Field(
..., description="The location where the parameter is sent."
)
description: Optional[str] = Field(None, description="A detailed description of the parameter.")
required: bool = Field(False, description="Whether the parameter is required.")
example: Optional[Any] = Field(None, description="An example value for the parameter.")
schema_: Optional[Dict[str, Any]] = Field(
None, alias="schema", description="JSON schema for complex object/array types."
)
class Response(BaseModel):
"""
Represents a possible response from an API endpoint.
"""
status_code: int = Field(..., description="The HTTP status code of the response.")
description: Optional[str] = Field(None, description="A description of the response.")
schema_: Optional[Dict[str, Any]] = Field(
None, alias="schema", description="JSON schema for the response body."
)
example: Optional[Any] = Field(None, description="An example response body.")
headers: Optional[Dict[str, str]] = Field(None, description="Example response headers.")
class Endpoint(BaseModel):
"""
Represents a single API endpoint.
"""
name: str = Field(..., description="A short, descriptive name for the endpoint.")
path: str = Field(..., description="The URL path of the endpoint (e.g., /users/{id}).")
method: Literal["GET", "POST", "PUT", "DELETE", "PATCH"] = Field(
..., description="The HTTP method for the endpoint."
)
summary: str = Field(..., description="A brief summary of what the endpoint does.")
description: Optional[str] = Field(None, description="A detailed description of the endpoint.")
tags: List[str] = Field([], description="Tags for grouping related endpoints.")
parameters: List[Parameter] = Field([], description="List of parameters for this endpoint.")
request_body: Optional[Dict[str, Any]] = Field(
None, description="JSON schema for the request body (if applicable)."
)
responses: List[Response] = Field(..., description="List of possible responses.")
security: Optional[List[Dict[str, List[str]]]] = Field(
None, description="Security requirements for this endpoint (e.g., [{'BearerAuth': []}])."
)
class AuthScheme(BaseModel):
"""
Represents an authentication scheme for the API.
"""
name: str = Field(..., description="The name of the authentication scheme (e.g., 'BearerAuth').")
type: Literal["apiKey", "http", "oauth2", "openIdConnect"] = Field(
..., description="The type of authentication scheme."
)
description: Optional[str] = Field(None, description="A description of how to use this scheme.")
# Specific fields for different types (simplified for example)
scheme: Optional[str] = Field(None, description="For HTTP auth, e.g., 'bearer'.")
bearer_format: Optional[str] = Field(None, description="For bearer auth, e.g., 'JWT'.")
in_: Optional[Literal["query", "header", "cookie"]] = Field(
None, alias="in", description="For apiKey, where the API key is located."
)
param_name: Optional[str] = Field(None, description="For apiKey, the name of the header/query param.")
class API(BaseModel):
"""
The top-level model representing the entire API documentation structure.
"""
title: str = Field(..., description="The title of the API.")
version: str = Field(..., description="The version of the API.")
description: Optional[str] = Field(None, description="A general description of the API.")
base_url: str = Field(..., description="The base URL for all API endpoints.")
auth_schemes: Dict[str, AuthScheme] = Field(
{}, description="Dictionary of authentication schemes available for the API."
)
endpoints: List[Endpoint] = Field(..., description="List of all API endpoints.")
Explanation:
Parameter: Defines individual parameters with their name, type, location (query, header, path, body, cookie), description, and whether they are required. Includes schema_ for complex types and example for direct values.Response: Describes a possible response, including its HTTP status code, description, and an optional JSON schema_ and example for the response body.Endpoint: The core definition of an API endpoint, encompassing its path, HTTP method, summary, detailed description, associated tags, a list of parameters, an optional request_body schema, and a list of possible responses. It also includes security requirements.AuthScheme: Models different authentication methods (e.g., API Key, HTTP Bearer) with their type, name, and specific configuration details.API: The root model that aggregates all information about the API, including its title, version, base URL, defined auth_schemes, and a list of all endpoints.example_generator.py)This utility helps in generating realistic JSON examples for request and response bodies based on their defined schemas. This is crucial for providing concrete examples in the documentation.
# example_generator.py
from typing import Dict, Any, List, Union
import random
import string
def generate_example_from_schema(schema: Dict[str, Any]) -> Any:
"""
Generates a mock example value based on a simplified JSON schema.
Supports basic types, objects, and arrays.
"""
if not isinstance(schema, dict):
return None # Invalid schema
_type = schema.get("type")
_format = schema.get("format")
_enum = schema.get("enum")
_example = schema.get("example")
if _example is not None:
return _example
if _enum:
return random.choice(_enum)
if _type == "string":
if _format == "date-time":
return "2023-10-27T10:00:00Z"
if _format == "uuid":
return "a1b2c3d4-e5f6-7890-1234-567890abcdef"
if _format == "email":
return "user@example.com"
return "".join(random.choices(string.ascii_lowercase + string.digits, k=10))
elif _type == "integer":
return random.randint(1, 100)
elif _type == "boolean":
return random.choice([True, False])
elif _type == "number":
return round(random.uniform(1.0, 100.0), 2)
elif _type == "array":
items_schema = schema.get("items", {})
min_items = schema.get("minItems", 1)
max_items = schema.get("maxItems", min_items + 1)
count = random.randint(min_items, max_items)
return [generate_example_from_schema(items_schema) for _ in range(count)]
elif _type == "object":
properties = schema.get("properties", {})
required = schema.get("required", [])
example_object = {}
for prop_name, prop_schema in properties.items():
if prop_name in required or random.random() > 0.3: # Include some optional fields
example_object[prop_name] = generate_example_from_schema(prop_schema)
return example_object
else:
return None # Unknown type
Explanation:
generate_example_from_schema(schema): This function takes a JSON schema dictionary and recursively generates a mock data structure that conforms to it.string, integer, boolean, number), as well as array and object types.date-time, uuid, and email to generate more realistic values.example and enum: Prioritizes explicit example values or enum choices if provided in the schema, ensuring accuracy.random to generate varying string, number, and boolean values, and to include optional object properties.markdown_renderer.py)This section provides a class to render the API model into a structured Markdown document. This is where the actual documentation content is assembled.
# markdown_renderer.py
import json
from typing import List, Dict, Any
from textwrap import indent
from api_models import API, Endpoint, Parameter, Response, AuthScheme
from example_generator import generate_example_from_schema
class MarkdownRenderer:
"""
Renders an API definition (API model) into a Markdown formatted string.
"""
def __init__(self, api: API):
self.api = api
self.output_lines: List[str] = []
def _add_line(self, line: str = ""):
"""Adds a line to the output, followed by a newline."""
self.output_lines.append(line)
def _add_code_block(self, code: str, lang: str = "json"):
"""Adds a code block to the output."""
self._add_line(f"```{lang}")
self._add_line(code)
self._add_line("```")
self._add_line()
def _render_parameters(self, parameters: List[Parameter]):
"""Renders a list of parameters into a Markdown table."""
if not parameters:
return
self._add_line("### Parameters")
self._add_line("| Name | Location | Type | Required | Description | Example |")
self._add_line("|---|---|---|---|---|---|")
for param in parameters:
example_val = param.example
if example_val is None and param.schema_:
# Attempt to generate example if schema is provided
example_val = generate_example_from_schema(param.schema_)
example_str = json.dumps(example_val) if example_val is not None else "N/A"
example_str = example_str.replace('|', '\\|') # Escape pipe for table
self._add_line(
f"| `{param.name}` "
f"| `{param.location}` "
f"| `{param.type}` "
f"| {'Yes' if param.required else 'No'} "
f"| {param.description or ''} "
f"| `{example_str}` |"
)
self._add_line()
def _render_request_body(self, request_body_schema: Optional[Dict[str, Any]]):
"""Renders the request body schema and example."""
if not request_body_schema:
return
self._add_line("### Request Body")
self._add_line("The request body should be a JSON object conforming to the following structure:")
self._add_code_block(json.dumps(request_body_schema, indent=2), lang="json")
example_body = generate_example_from_schema(request_body_schema)
if example_body:
self._add_line("Example Request
Welcome to the comprehensive documentation for the Product Management API. This guide provides detailed information on how to integrate with our API, manage your products programmatically, and leverage its full capabilities.
The Product Management API allows you to programmatically manage your product catalog, including creating, retrieving, updating, and deleting product information. This API is designed for developers who need to integrate product data into their applications, websites, or internal systems.
Key Features:
Getting Started:
All API requests should be made to the following base URL:
https://api.yourcompany.com/v1
The Product Management API uses API Key authentication. You must include your unique API Key in the X-API-Key header for every request.
How to Authenticate:
Your API Key is available in your Developer Dashboard under "API Settings". Treat your API Key as a sensitive credential and keep it confidential. Do not expose it in client-side code or public repositories.
Pass your API Key in the X-API-Key HTTP header for every request.
Example (cURL):
curl -X GET \
'https://api.yourcompany.com/v1/products' \
-H 'Accept: application/json' \
-H 'X-API-Key: YOUR_API_KEY_HERE'
Example (Python using requests):
import requests
api_key = "YOUR_API_KEY_HERE"
headers = {
"X-API-Key": api_key,
"Accept": "application/json"
}
response = requests.get("https://api.yourcompany.com/v1/products", headers=headers)
print(response.json())
The API uses standard HTTP status codes to indicate the success or failure of an API request. In case of an error, the API will return a JSON object with details about the error.
Common HTTP Status Codes:
| Status Code | Meaning | Description |
| :---------- | :--------------------------- | :--------------------------------------------------------------------------- |
| 200 OK | Success | The request was successful. |
| 201 Created | Resource Created | The request resulted in a new resource being created. |
| 204 No Content | Success (No Content) | The request was successful, but there is no content to return (e.g., DELETE).|
| 400 Bad Request | Invalid Input | The request was malformed or contained invalid parameters. |
| 401 Unauthorized | Authentication Required | No valid API Key provided, or authentication failed. |
| 403 Forbidden | Access Denied | The authenticated user does not have permission to access the resource. |
| 404 Not Found | Resource Not Found | The requested resource does not exist. |
| 405 Method Not Allowed | Invalid HTTP Method | The HTTP method used is not supported for this endpoint. |
| 429 Too Many Requests | Rate Limit Exceeded | You have sent too many requests in a given amount of time. |
| 500 Internal Server Error | Server Error | An unexpected error occurred on the server. |
Example Error Response:
{
"code": "invalid_api_key",
"message": "The provided API Key is invalid or missing.",
"details": "Please ensure you are using a valid API Key in the X-API-Key header."
}
To ensure fair usage and system stability, the Product Management API applies rate limits.
* X-RateLimit-Limit: The maximum number of requests allowed in the current rate limit window.
* X-RateLimit-Remaining: The number of requests remaining in the current rate limit window.
* X-RateLimit-Reset: The time at which the current rate limit window resets (UTC epoch seconds).
If you exceed the rate limit, you will receive a 429 Too Many Requests HTTP status code.
This section details all available API endpoints, including their methods, paths, descriptions, parameters, and examples.
Retrieves a list of all products. Supports pagination and filtering.
GET /productsProduct objects. * limit (optional, integer): Maximum number of products to return. Default is 10, max is 100.
* offset (optional, integer): Number of products to skip before starting to collect the result set. Default is 0.
* category (optional, string): Filter products by category.
* status (optional, enum: active, inactive): Filter products by status.
curl -X GET \
'https://api.yourcompany.com/v1/products?limit=5&category=Electronics' \
-H 'Accept: application/json' \
-H 'X-API-Key: YOUR_API_KEY_HERE'
{
"data": [
{
"id": "prod_001",
"name": "Wireless Headphones",
"description": "Premium wireless headphones with noise cancellation.",
"price": 199.99,
"currency": "USD",
"category": "Electronics",
"status": "active",
"createdAt": "2023-01-15T10:00:00Z",
"updatedAt": "2023-01-15T10:00:00Z"
},
{
"id": "prod_002",
"name": "Smartwatch Pro",
"description": "Advanced smartwatch with health tracking features.",
"price": 249.00,
"currency": "USD",
"category": "Electronics",
"status": "active",
"createdAt": "2023-02-01T11:30:00Z",
"updatedAt": "2023-02-01T11:30:00Z"
}
],
"meta": {
"total": 2,
"limit": 5,
"offset": 0
}
}
Retrieves a single product by its unique identifier.
GET /products/{productId}Product object. * productId (required, string): The unique identifier of the product.
curl -X GET \
'https://api.yourcompany.com/v1/products/prod_001' \
-H 'Accept: application/json' \
-H 'X-API-Key: YOUR_API_KEY_HERE'
{
"id": "prod_001",
"name": "Wireless Headphones",
"description": "Premium wireless headphones with noise cancellation.",
"price": 199.99,
"currency": "USD",
"category": "Electronics",
"status": "active",
"createdAt": "2023-01-15T10:00:00Z",
"updatedAt": "2023-01-15T10:00:00Z"
}
{
"code": "product_not_found",
"message": "Product with ID 'prod_999' not found.",
"details": "The requested product does not exist in the catalog."
}
Creates a new product in the catalog.
POST /productsProduct and returns the created Product object. * name (required, string): The name of the product.
* description (optional, string): A brief description of the product.
* price (required, number): The price of the product. Must be positive.
* currency (required, string): The currency code (e.g., "USD", "EUR").
* category (required, string): The category the product belongs to.
* status (optional, enum: active, inactive): The status of the product. Default is active.
curl -X POST \
'https://api.yourcompany.com/v1/products' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-API-Key: YOUR_API_KEY_HERE' \
-d '{
"name": "Ergonomic Keyboard",
"description": "Comfortable mechanical keyboard for daily use.",
"price": 120.00,
"currency": "USD",
"category": "Peripherals",
"status": "active"
}'
{
"id": "prod_003",
"name": "Ergonomic Keyboard",
"description": "Comfortable mechanical keyboard for daily use.",
"price": 120.00,
"currency": "USD",
"category": "Peripherals",
"status": "active",
"createdAt": "2023-03-01T09:00:00Z",
"updatedAt": "2023-03-01T09:00:00Z"
}
{
"code": "validation_error",
"message": "Validation failed for request body.",
"details": [
{
"field": "name",
"message": "Product name is required."
}
]
}
Updates an existing product identified by its ID. Only provided fields will be updated.
PUT /products/{productId}Product and returns the updated Product object. * productId (required, string): The unique identifier of the product to update.
* name (optional, string): The new name of the product.
* description (optional, string): The new description of the product.
* price (optional, number): The new price of the product.
* currency (optional, string): The new currency code.
* category (optional, string): The new category.
* status (optional, enum: active, inactive): The new status of the product.
curl -X PUT \
'https://api.yourcompany.com/v1/products/prod_001' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-API-Key: YOUR_API_KEY_HERE' \
-d '{
"price": 189.99,
"status": "inactive"
}'
{
"id": "prod_001",
"name": "Wireless Headphones",
"description": "Premium wireless headphones with noise cancellation.",
"price": 189.99,
"currency": "USD",
"category": "Electronics",
"status": "inactive",
"createdAt": "2023-01-15T10:00:00Z",
"updatedAt": "2023-03-05T14:30:00Z"
}
Deletes a product from the catalog. This action is irreversible.
DELETE /products/{productId}Product identified by its ID. * productId (required, string): The unique identifier of the product to delete.
curl -X DELETE \
'https://api.yourcompany.com/v1/products/prod_003' \
-H 'X-API-Key: YOUR_API_KEY_HERE'
(No response body is returned for successful DELETE operations.)
{
"code": "product_not_found",
"message": "Product with ID 'prod_999' not found.",
"details": "The product you are trying to delete does not exist."
}
This section describes the structure of the data objects used in the API.
The core object representing a product in the catalog.
| Field | Type | Description | Required |
| :---------- | :-------- | :--------------------------------------------------- | :------- |
| id | string | Unique identifier for the product. | Read-only |
| name | string | The name of the product. | Yes |
| description | string | A brief description of the product. | No |
| price | number
\n