FastAPI: How to Display XML Responses in Docs
I. Introduction: The Evolving Landscape of API Documentation and FastAPI's Prowess
In the dynamic world of modern software development, Application Programming Interfaces (APIs) stand as the fundamental building blocks, enabling seamless communication and data exchange between disparate systems. From mobile applications interacting with backend services to intricate microservices architectures facilitating complex business logic, APIs are the silent orchestrators of digital ecosystems. Yet, the sheer ubiquity of APIs introduces a critical challenge: discoverability and usability. Without clear, comprehensive, and up-to-date documentation, even the most elegantly designed API can become an impenetrable black box, hindering adoption and increasing integration friction.
This is where frameworks like FastAPI shine with exceptional brilliance. FastAPI, a modern, fast (high-performance) web framework for building APIs with Python 3.7+ based on standard Python type hints, has rapidly gained traction among developers. Its core strengths lie not only in its remarkable speed and asynchronous capabilities but also, crucially, in its automatic generation of interactive API documentation. By leveraging industry standards like OpenAPI (formerly Swagger) and JSON Schema, FastAPI effortlessly transforms Python type hints into detailed, browsable documentation interfaces like Swagger UI and ReDoc. This automatic documentation is a game-changer, significantly reducing the manual effort traditionally associated with API specification and ensuring that the documentation remains perpetually synchronized with the codebase.
The vast majority of modern web APIs, especially RESTful services, primarily communicate using JSON (JavaScript Object Notation). Its lightweight nature, human-readability, and native compatibility with JavaScript environments have made it the de facto standard for data interchange. FastAPI, in its default configuration, naturally aligns with this JSON-centric paradigm. Its Pydantic models, which are central to data validation and serialization, are inherently designed to map Python objects to and from JSON structures, and consequently, to generate JSON Schemas for OpenAPI.
However, despite JSON's widespread dominance, XML (Extensible Markup Language) continues to hold a significant and often indispensable position in various domains. Whether integrating with entrenched legacy enterprise systems, adhering to specific industry standards (e.g., financial services, healthcare, telecommunications), or handling document-oriented data where strict schema validation is paramount, XML remains a vital data format. A modern FastAPI application, therefore, might frequently encounter scenarios where it needs to produce XML responses, either to serve specific client requirements or to act as a bridge to older systems.
The core problem arises when a FastAPI application, which defaults to JSON, needs to clearly articulate in its automatically generated documentation that certain endpoints return XML, not JSON. The standard Swagger UI and ReDoc interfaces, while excellent for JSON, don't inherently know how to represent an application/xml response type without explicit guidance. Developers often find their XML responses working perfectly, but the documentation portal still misleadingly suggests a JSON output, or worse, provides no structural information for the XML payload. This discrepancy creates confusion for API consumers and undermines the very purpose of robust API documentation.
This comprehensive article aims to dissect this challenge, providing an in-depth exploration of how to configure FastAPI to not only produce XML responses effectively but, more importantly, to ensure these XML responses are accurately and informatively displayed within the interactive OpenAPI documentation. We will delve into the underlying mechanisms of FastAPI, explore various methods for XML serialization, and meticulously detail the techniques required to properly describe XML payloads within the generated API documentation, thus bridging the gap between implementation and clear communication.
II. FastAPI's Foundation: Pydantic, OpenAPI, and the JSON-Centric Default
To truly grasp how to instruct FastAPI's documentation about XML responses, we must first understand the fundamental pillars upon which FastAPI is built and how its automatic documentation process functions. This understanding will reveal why FastAPI naturally gravitates towards JSON and where the explicit intervention is required for alternative data formats like XML.
The Power of Pydantic: Data Validation and Serialization
At the heart of FastAPI's data handling capabilities lies Pydantic, a Python library that enables data validation and settings management using Python type annotations. Pydantic is not just a type checker; it's a runtime validator. When you define a Pydantic model, you're not just providing type hints for your editor; you're creating a robust data schema that FastAPI leverages extensively.
Consider a simple Pydantic model:
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str = Field(..., example="Smartphone X")
description: str | None = Field(None, example="Latest model with AI camera")
price: float = Field(..., example=799.99)
tax: float | None = Field(None, example=0.08)
class Config:
schema_extra = {
"example": {
"name": "Laptop Pro",
"description": "High-performance laptop for professionals",
"price": 1499.00,
"tax": 120.00
}
}
When this Item model is used as a request body or response model in a FastAPI endpoint, Pydantic performs several crucial functions: 1. Validation: It ensures that incoming request data conforms to the specified types and constraints (e.g., name must be a string, price must be a float). If the data doesn't match, it automatically raises clear validation errors. 2. Serialization: It converts Python objects into dictionary-like structures suitable for JSON output, and vice-versa for incoming JSON payloads. 3. Documentation Generation: Critically for our discussion, Pydantic models are automatically translated into JSON Schema. JSON Schema is a declarative language that allows you to annotate and validate JSON documents. It's the language OpenAPI uses to describe data structures.
OpenAPI: The Blueprint for APIs
OpenAPI, formerly known as Swagger, is a language-agnostic, human-readable specification for describing RESTful APIs. It provides a standardized format (YAML or JSON) to describe an API's: * Endpoints (paths) * Operations (GET, POST, PUT, DELETE, etc.) * Parameters (path, query, header, cookie) * Request bodies * Response structures (including status codes and content types) * Authentication methods * And much more.
The primary benefit of OpenAPI is that once an API is described in this format, various tools can consume it to: * Generate interactive documentation (like Swagger UI and ReDoc). * Generate client SDKs in various programming languages. * Generate server stubs. * Perform automated testing. * Power API management platforms.
FastAPI ingeniously integrates with OpenAPI. When you define endpoints and specify Pydantic models using type hints, FastAPI automatically generates the corresponding OpenAPI specification document (/openapi.json). This dynamic generation is why your API documentation is always up-to-date with your code; there's no separate documentation to maintain manually.
How FastAPI Leverages Pydantic and OpenAPI for Auto-Documentation
Let's illustrate with a basic FastAPI endpoint that returns JSON:
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import List, Optional
app = FastAPI(
title="JSON Default API",
description="A simple API showcasing FastAPI's default JSON behavior and auto-documentation."
)
class Product(BaseModel):
product_id: str = Field(..., example="prod-123")
name: str = Field(..., example="Ergonomic Keyboard")
category: str = Field(..., example="Peripherals")
price: float = Field(..., example=120.50)
in_stock: bool = Field(True, description="Availability status of the product")
class Config:
json_schema_extra = {
"example": {
"product_id": "prod-456",
"name": "Wireless Mouse",
"category": "Peripherals",
"price": 45.00,
"in_stock": True
}
}
@app.get("/techblog/en/products/{product_id}", response_model=Product, summary="Retrieve a single product by ID")
async def get_product(product_id: str):
"""
Fetches details for a specific product using its unique ID.
If the product is not found, a 404 error is returned.
"""
# In a real application, this would fetch data from a database
if product_id == "prod-123":
return Product(product_id="prod-123", name="Ergonomic Keyboard", category="Peripherals", price=120.50, in_stock=True)
return {"detail": "Product not found"}
@app.get("/techblog/en/products/", response_model=List[Product], summary="List all available products")
async def list_products(limit: int = 10, offset: int = 0):
"""
Retrieves a list of products with pagination options.
"""
products_data = [
Product(product_id="prod-123", name="Ergonomic Keyboard", category="Peripherals", price=120.50, in_stock=True),
Product(product_id="prod-456", name="Wireless Mouse", category="Peripherals", price=45.00, in_stock=True),
Product(product_id="prod-789", name="Monitor Stand", category="Accessories", price=80.00, in_stock=False)
]
return products_data[offset:offset + limit]
When you run this application and navigate to /docs (Swagger UI) or /redoc, you'll see beautifully rendered documentation for these endpoints. * FastAPI uses the Pydantic Product model to infer the schema of the request/response bodies. * This schema is then converted into JSON Schema and embedded within the OpenAPI specification. * Swagger UI/ReDoc reads this OpenAPI spec and displays the Product schema, including field types, descriptions, and examples (if provided via Field or json_schema_extra). * Crucially, for responses, FastAPI defaults the Content-Type header to application/json in the OpenAPI spec, and thus in the documentation. This is because Pydantic's native serialization is to JSON, and there's no explicit instruction otherwise.
This implicit assumption of JSON is perfectly fine for 99% of modern API development. However, it becomes a point of concern when your API needs to deviate from this default and return data in a different format, such as XML. The documentation will continue to suggest JSON, potentially confusing API consumers who are expecting or requiring XML. The remainder of this article will focus on how to address this specific challenge.
III. The Enduring Presence of XML in Modern API Development
While JSON has undeniably become the dominant data interchange format for modern web APIs, particularly within the realm of RESTful services and microservices, it's a misconception to assume that XML (Extensible Markup Language) has been entirely relegated to the annals of computing history. In many critical sectors and specific integration scenarios, XML not only persists but thrives, often as an indispensable component of robust and reliable systems. Understanding why XML maintains its relevance is crucial for developers building versatile APIs with frameworks like FastAPI.
Historical Context: XML's Reign and SOAP
XML burst onto the scene in the late 1990s as a successor to SGML, designed for sharing structured data across the internet. Its self-descriptive nature, hierarchical structure, and extensibility made it a powerful tool for representing complex information. For a significant period, XML was the undisputed king of web service communication, most notably through SOAP (Simple Object Access Protocol). SOAP, with its strict, verbose, and contract-first approach, relied heavily on XML for message formatting and WSDL (Web Services Description Language) for interface description. While SOAP and WSDL have largely been supplanted by REST and JSON in new greenfield projects due to their perceived complexity and overhead, millions of legacy systems globally still operate on these foundations.
Use Cases Where XML is Still Preferred or Necessary
- Legacy Systems Integration: This is perhaps the most pervasive reason for XML's continued existence. Large enterprises, particularly in finance, government, and manufacturing, have significant investments in systems that were built decades ago and expose their data and functionality exclusively via XML-based interfaces (e.g., SOAP, bespoke XML APIs). When a modern FastAPI application needs to communicate with or act as a gateway to these systems, it must be capable of consuming and producing XML. Rewriting these legacy systems is often economically unfeasible or too risky, making XML a necessary bridge.
- Specific Industry Standards and Regulatory Compliance: Numerous industries have established rigorous, often regulatory-driven, standards that mandate the use of XML for data exchange.
- Financial Services: Standards like FIXML (Financial Information eXchange Markup Language) for trading, SWIFT MT/MX for international payments, and XBRL (eXtensible Business Reporting Language) for financial reporting are deeply embedded. These standards leverage XML's strong schema validation capabilities to ensure data integrity and compliance.
- Healthcare: HL7 (Health Level Seven) for clinical data exchange, though sometimes using JSON or other formats, still has strong XML profiles. CDA (Clinical Document Architecture) documents are XML-based.
- Government: Many government agencies globally use XML for reporting and data submission (e.g., tax data, legal filings) due to its formal structure and validation features.
- Telecommunications: Network configuration, billing, and provisioning systems often rely on XML.
- Publishing and Content Management: Formats like DocBook and DITA (Darwin Information Typing Architecture) for technical documentation, or various publishing industry XML standards (e.g., JATS for scientific journals), leverage XML's structural properties for content representation and transformation.
- Data Interchange Formats Requiring Strict Schema Validation (XSD): One of XML's most powerful features is its tight coupling with XML Schema Definition (XSD). XSDs allow for extremely precise and rigorous validation of XML documents, defining data types, element relationships, cardinality, and even complex structural rules. While JSON Schema exists, XML Schema is often considered more mature and powerful for highly complex and strictly controlled data structures, making it ideal for scenarios where data integrity and adherence to a predefined contract are paramount. For instance, if an API needs to guarantee that every incoming or outgoing message precisely matches a governmental or industry-mandated schema, XML with XSD provides a robust mechanism.
- Human-Readable Documents as Data: In scenarios where the "data" itself is essentially a structured document meant to be human-readable, XML can sometimes offer advantages. For instance, configuration files, certain types of reports, or documents that are frequently transformed via XSLT (Extensible Stylesheet Language Transformations) benefit from XML's inherent document-centric model.
Pros and Cons of XML vs. JSON
To further contextualize XML's continued role, let's briefly compare its characteristics with JSON:
| Feature | XML (Extensible Markup Language) | JSON (JavaScript Object Notation) |
|---|---|---|
| Verbosity | More verbose, requires opening and closing tags for each element. | Less verbose, uses key-value pairs and arrays. |
| Human Readability | Generally less concise, can be harder to visually parse complex structures. | Very concise, easy to read and understand, especially for nested data. |
| Schema Enforcement | Excellent with XSD, providing strong, formal validation. | Good with JSON Schema, but generally less mature/expressive than XSD. |
| Data Types | All data is text within elements/attributes; types defined by XSD. | Native support for strings, numbers, booleans, objects, arrays, null. |
| Tooling/Ecosystem | Mature tooling for parsing (DOM, SAX), transformation (XSLT), validation (XSD). | Extensive tooling in virtually all programming languages; native to JavaScript. |
| Comments | Supports comments (<!-- comment -->). |
Does not officially support comments within the data itself. |
| Attributes | Supports attributes on elements for metadata. | No direct equivalent; metadata usually nested as key-value pairs. |
| Namespace Support | Robust support for XML Namespaces to avoid element name collisions. | No direct equivalent for namespaces. |
| Parsing Complexity | Can be more complex due to DOM/SAX parsers, attributes, namespaces. | Generally simpler parsing into native language data structures. |
| Network Overhead | Higher due to verbose tags. | Lower due to compact syntax. |
Why a Developer Might Need to Return XML from a FastAPI Service
Given these points, a FastAPI developer might be compelled to return XML for several compelling reasons: * API Gateway/Proxy: The FastAPI application acts as an intermediary, receiving requests, potentially transforming them, and then forwarding them to a backend system that only understands or responds with XML. The FastAPI service then translates this into a modern JSON API for its clients, or vice-versa. * Specific Client Requirements: A particular client application, perhaps a legacy desktop application or a specialized industry tool, expects XML responses and cannot easily process JSON. * Adherence to Industry Standards: The API needs to conform to an industry-specific data exchange standard that mandates XML. * Document Generation: The API's purpose is to generate XML documents (e.g., reports, configuration files) that are then consumed by other systems or transformed for display.
In all these scenarios, simply producing XML is only half the battle. The other, equally crucial half, is effectively communicating to API consumers through the documentation that an XML response is expected, what its structure looks like, and what media type (application/xml) it carries. This is precisely the challenge we will tackle in the subsequent sections.
IV. Crafting XML Responses in FastAPI: Beyond the Default
Before we can document XML responses, we must first learn how to effectively generate them within a FastAPI application. FastAPI's default response type is JSON, managed by fastapi.responses.JSONResponse. To return XML, we need to explicitly tell FastAPI to use a different response class or construct the XML content ourselves and package it correctly.
Method 1: Using Response Objects Directly with XMLResponse
FastAPI provides a base Response class in fastapi.responses that allows for highly flexible control over the response content and headers. While there isn't a built-in XMLResponse class per se in FastAPI's standard library (unlike HTMLResponse or PlainTextResponse), creating one is straightforward. However, the most direct way to return XML without a custom class is to use the generic Response class and specify the media_type.
Let's illustrate how to create a simple XMLResponse equivalent using fastapi.responses.Response:
from fastapi import FastAPI, Response
from typing import Optional
app = FastAPI(
title="XML Response Examples",
description="Demonstrates various ways to return XML from FastAPI endpoints."
)
@app.get("/techblog/en/items/xml-string", summary="Get a simple XML item as a string")
async def get_item_xml_string():
"""
Returns a simple XML document directly as a string, specifying the media type.
"""
xml_content = """<?xml version="1.0" encoding="UTF-8"?>
<item>
<name>Laptop Pro</name>
<description>High-performance laptop</description>
<price>1499.00</price>
<currency>USD</currency>
</item>"""
return Response(content=xml_content, media_type="application/xml")
@app.get("/techblog/en/data/plain-xml", response_class=Response, summary="Get simple XML with response_class")
async def get_plain_xml_with_class():
"""
Demonstrates returning XML using `response_class=Response` and specifying `media_type`.
"""
xml_data = "<root><message>Hello from FastAPI XML!</message><timestamp>2023-10-27T10:00:00Z</timestamp></root>"
return Response(content=xml_data, media_type="application/xml")
In this example, we directly instantiate Response with our XML string and critically set media_type="application/xml". This tells FastAPI (and the client) that the content being returned is XML.
Creating a Reusable XMLResponse Class: For better code organization and reusability, you might want to create your own XMLResponse class, similar to how HTMLResponse or PlainTextResponse are structured:
from fastapi.responses import Response as BaseResponse
class XMLResponse(BaseResponse):
media_type = "application/xml"
# Now you can use it like this:
@app.get("/techblog/en/items/custom-xml", response_class=XMLResponse, summary="Get an item using a custom XMLResponse class")
async def get_item_custom_xml():
"""
Returns an XML document using a custom XMLResponse class for clarity and reusability.
"""
xml_content = """<?xml version="1.0" encoding="UTF-8"?>
<product>
<id>P101</id>
<title>Advanced Coffee Maker</title>
<category>Kitchen Appliances</category>
<status>In Stock</status>
</product>"""
return xml_content # The content will be automatically wrapped by XMLResponse
By setting response_class=XMLResponse, FastAPI will automatically wrap the returned Python string (or bytes) in an XMLResponse object, ensuring the correct Content-Type header is set.
Method 2: Leveraging XML Serialization Libraries
While returning raw XML strings is feasible for simple cases, constructing complex or dynamic XML structures by hand can quickly become cumbersome and error-prone. Python offers excellent libraries for programmatically building and parsing XML.
a) xml.etree.ElementTree: Python's Built-in
xml.etree.ElementTree is Python's standard library for XML parsing and generation. It's lightweight, efficient, and requires no external dependencies. It's suitable for moderately complex XML structures.
import xml.etree.ElementTree as ET
from fastapi import FastAPI, Response
# ... (FastAPI app setup from before) ...
@app.get("/techblog/en/report/elementtree", summary="Generate a dynamic XML report using ElementTree")
async def get_report_elementtree(report_id: str = "monthly"):
"""
Generates a dynamic XML report for a given ID using Python's built-in ElementTree library.
"""
root = ET.Element("report", id=report_id)
title = ET.SubElement(root, "title")
title.text = f"Sales Report for {report_id.capitalize()}"
date_node = ET.SubElement(root, "date")
date_node.text = "2023-10-27"
data_node = ET.SubElement(root, "data")
item1 = ET.SubElement(data_node, "item", category="electronics")
item1_name = ET.SubElement(item1, "name")
item1_name.text = "Smartphone"
item1_sales = ET.SubElement(item1, "sales")
item1_sales.text = "120000"
item2 = ET.SubElement(data_node, "item", category="books")
item2_name = ET.SubElement(item2, "name")
item2_name.text = "Fiction Novel"
item2_sales = ET.SubElement(item2, "sales")
item2_sales.text = "35000"
xml_string = ET.tostring(root, encoding='utf-8', xml_declaration=True).decode('utf-8')
return Response(content=xml_string, media_type="application/xml")
Pros: * Built-in, no extra installation. * Good for programmatically building XML. * Supports basic XML features like elements, attributes, text.
Cons: * Can become verbose for very complex structures. * Lacks advanced features like XPath 2.0, XSLT, schema validation compared to lxml.
b) lxml: Powerful and Fast
lxml is a robust, feature-rich, and fast XML and HTML toolkit for Python. It's a binding to the C libraries libxml2 and libxslt, which makes it very efficient. If you're dealing with very large XML documents, need advanced XML features (like XPath, XSLT, DTD/XML Schema validation), or desire high performance, lxml is the go-to choice.
First, you'll need to install it: pip install lxml.
from fastapi import FastAPI, Response
from lxml import etree # Using lxml's etree module
# ... (FastAPI app setup from before) ...
@app.get("/techblog/en/config/lxml", summary="Generate complex XML configuration using lxml")
async def get_config_lxml(device_id: str = "server-001"):
"""
Generates a more complex XML configuration for a device, including namespaces, using lxml.
"""
# Define namespaces
nsmap = {
None: "http://example.com/config/v1", # Default namespace
"hw": "http://example.com/hardware/v1"
}
# Create root element with default namespace
root = etree.Element("{http://example.com/config/v1}deviceConfig", nsmap=nsmap)
# Add elements
device_id_elem = etree.SubElement(root, "{http://example.com/config/v1}deviceId")
device_id_elem.text = device_id
network_elem = etree.SubElement(root, "{http://example.com/config/v1}networkSettings")
ip_elem = etree.SubElement(network_elem, "{http://example.com/config/v1}ipAddress")
ip_elem.text = "192.168.1.100"
port_elem = etree.SubElement(network_elem, "{http://example.com/config/v1}port")
port_elem.text = "8080"
# Add hardware element with its own namespace
hardware_elem = etree.SubElement(root, "{http://example.com/hardware/v1}hardwareInfo")
cpu_elem = etree.SubElement(hardware_elem, "{http://example.com/hardware/v1}cpu")
cpu_elem.set("cores", "8")
cpu_elem.text = "Intel Xeon"
# Serialize to string
xml_string = etree.tostring(root, pretty_print=True, encoding='UTF-8', xml_declaration=True).decode('utf-8')
return Response(content=xml_string, media_type="application/xml")
Pros: * Extremely fast and memory efficient. * Full support for XPath 1.0/2.0, XSLT 1.0/2.0/3.0. * Excellent for parsing and manipulating existing XML documents. * Robust namespace handling. * XML Schema validation capabilities.
Cons: * Requires C libraries (libxml2, libxslt), which can sometimes complicate installation, especially on Windows or in constrained environments.
c) pydantic-xml: Bridging Pydantic and XML
pydantic-xml is a relatively new and exciting library that attempts to bridge the gap between Pydantic's powerful data validation and Python's XML serialization needs. It allows you to define XML structures using Pydantic models, much like you would for JSON, but with specific decorators and field types to map to XML elements, attributes, and text. This approach offers a consistent way to handle both JSON and XML data models within your FastAPI application.
First, install it: pip install pydantic-xml.
from fastapi import FastAPI, Response
from pydantic import Field
from pydantic_xml import BaseXmlModel, attr, element
from typing import List, Optional
# ... (FastAPI app setup from before) ...
class Address(BaseXmlModel):
street: str = element()
city: str = element()
zip_code: str = element(tag="zipCode") # Map to a different XML tag name
class Customer(BaseXmlModel, tag="customer"): # Define root tag for the model
customer_id: str = attr(name="id") # Map to an XML attribute
name: str = element()
email: Optional[str] = element(default=None)
address: Address = element()
orders: List[str] = element(tag="orderId", default_factory=list) # List of elements
class Config:
xml_declaration = True # Include XML declaration
indent = 4 # Pretty print
@app.get("/techblog/en/customer/pydantic-xml/{customer_id}", response_class=XMLResponse, summary="Get customer data as XML using pydantic-xml")
async def get_customer_pydantic_xml(customer_id: str):
"""
Retrieves customer details and returns them as a structured XML document using pydantic-xml.
"""
customer_data = Customer(
customer_id=customer_id,
name="John Doe",
email="john.doe@example.com",
address=Address(street="123 Main St", city="Anytown", zip_code="12345"),
orders=["ORD-001", "ORD-002"]
)
# pydantic-xml automatically handles serialization to XML string
xml_string = customer_data.model_dump_xml()
return xml_string # XMLResponse will handle media_type
Pros: * Leverages familiar Pydantic syntax for XML model definition. * Provides data validation for XML just like Pydantic does for JSON. * Automatically handles serialization and deserialization between Python objects and XML. * Can specify XML element names, attributes, and text content directly in the model. * Supports XML namespaces, lists of elements, and nested structures.
Cons: * Still a relatively new library, so community support and advanced examples might be less abundant than for lxml. * May not cover every esoteric XML feature or be as performant as lxml for extreme cases.
Integrating with FastAPI Endpoints: Returning the XML
Regardless of which serialization method you choose (raw string, ElementTree, lxml, pydantic-xml), the final step is to return the generated XML content from your FastAPI endpoint. The most robust way to do this is by explicitly setting the response_class for your route decorator to a custom XMLResponse (or Response with media_type explicitly set), as demonstrated in the examples above.
# Re-iterating the pattern for clarity
from fastapi import FastAPI
from fastapi.responses import Response
app = FastAPI()
class XMLResponse(Response):
media_type = "application/xml"
@app.get("/techblog/en/my-xml-endpoint", response_class=XMLResponse)
async def my_xml_endpoint():
xml_content = "<data><message>Hello XML!</message></data>"
return xml_content # The XMLResponse class will wrap this and set headers
By employing these techniques, your FastAPI application is now fully capable of generating and serving XML responses. The next, and arguably more critical, step is to ensure that your API's documentation accurately reflects these XML outputs, providing clarity and preventing confusion for consumers.
APIPark is a high-performance AI gateway that allows you to securely access the most comprehensive LLM APIs globally on the APIPark platform, including OpenAI, Anthropic, Mistral, Llama2, Google Gemini, and more.Try APIPark now! πππ
V. The Core Challenge: Informing OpenAPI Documentation about XML Responses
We've established how to produce XML responses from FastAPI. Now, the actual hurdle: making sure the automatically generated OpenAPI documentation (displayed in Swagger UI or ReDoc) accurately reflects that an endpoint returns XML, not the default JSON, and ideally provides some insight into the XML's structure or an example. The standard response_model parameter in FastAPI, while excellent for Pydantic models (and thus JSON), doesn't inherently understand how to translate an XMLResponse into a meaningful OpenAPI schema description for XML.
The problem arises because FastAPI's default OpenAPI schema generation pipeline primarily focuses on application/json content types derived from Pydantic models. When you return a Response(content=xml_string, media_type="application/xml") or use a custom XMLResponse, FastAPI correctly sets the HTTP Content-Type header for the actual response. However, it doesn't automatically inject this content type and an associated XML schema into the OpenAPI specification document (/openapi.json) for that specific operation. The documentation tools will either show nothing specific for XML, or worse, default to application/json based on the absence of explicit XML documentation.
Solution 1: Explicitly Defining responses in the APIRoute Decorator
The most direct and widely recommended method to document XML responses in FastAPI is to use the responses parameter available in FastAPI's path operation decorators (e.g., @app.get, @app.post). This parameter allows you to explicitly define possible responses for an operation, including different HTTP status codes, descriptions, and crucially, different content types with their associated schemas or examples.
The responses parameter expects a dictionary where keys are HTTP status codes (as integers or strings) and values are dictionaries describing the response. Each response dictionary can contain: * description: A human-readable text explaining the response. * content: A dictionary where keys are media types (e.g., "application/json", "application/xml") and values are dictionaries describing the content. * headers: (Optional) A dictionary describing response headers. * links: (Optional) A dictionary defining operation links.
The content dictionary is where we specify application/xml. Within the application/xml entry, we can define a schema and/or example.
Key Elements for Documenting XML within responses:
- Specifying
application/xml: You must explicitly state thatapplication/xmlis a possible content type for a given HTTP status code. - Defining a
schemafor XML: Unlike JSON, where Pydantic models directly translate to JSON Schema, there isn't a direct standard for "XML Schema" within OpenAPI'sschemaobject in the same way. However, you can provide hints or basic structure.- Simplest approach: Declare the schema as a
stringwith aformathint:json {"type": "string", "format": "xml"}This tells the documentation that the response is a string that represents XML. It's minimal but informative. - More detailed with
example: The most effective way to convey the structure of an XML response in OpenAPI is by providing anexampleof the XML payload directly within the schema definition. Thisexamplefield is often rendered beautifully by Swagger UI, allowing users to see exactly what XML to expect.
- Simplest approach: Declare the schema as a
Let's put this into practice with a detailed code example, building upon our previous XML generation methods.
from fastapi import FastAPI, Response
from pydantic_xml import BaseXmlModel, attr, element
from typing import List, Optional
app = FastAPI(
title="FastAPI XML Docs Example",
description="Demonstrates how to document XML responses using the 'responses' parameter.",
version="1.0.0"
)
# Custom XMLResponse class for clarity
class XMLResponse(Response):
media_type = "application/xml"
# Example Pydantic-XML model for documentation and serialization
class ProductItem(BaseXmlModel, tag="productItem"):
item_id: str = attr(name="id")
name: str = element()
description: Optional[str] = element(default=None)
price: float = element()
currency: str = element(default="USD")
class Config:
xml_declaration = True
indent = 4
# Define a more complex structure for a list of products
class ProductCatalog(BaseXmlModel, tag="catalog"):
products: List[ProductItem] = element(tag="product") # A list of ProductItem, each wrapped in <product>
class Config:
xml_declaration = True
indent = 4
# Example of a direct XML string
SAMPLE_XML_ITEM = """<?xml version="1.0" encoding="UTF-8"?>
<productItem id="PROD-001">
<name>Wireless Headphones</name>
<description>High-fidelity audio experience.</description>
<price>199.99</price>
<currency>EUR</currency>
</productItem>"""
# Example of a complex XML catalog
SAMPLE_XML_CATALOG = """<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<product id="PROD-001">
<name>Wireless Headphones</name>
<description>High-fidelity audio experience.</description>
<price>199.99</price>
<currency>EUR</currency>
</product>
<product id="PROD-002">
<name>Smartwatch X</name>
<price>299.00</price>
<currency>USD</currency>
</product>
</catalog>"""
@app.get(
"/techblog/en/products/single-xml/{item_id}",
response_class=XMLResponse,
summary="Get a single product as XML",
responses={
200: {
"description": "Successfully retrieved product details in XML format.",
"content": {
"application/xml": {
"schema": {
"type": "string",
"format": "xml",
"example": SAMPLE_XML_ITEM # This is key for docs!
}
}
}
},
404: {
"description": "Product not found.",
"content": {
"application/json": { # Even for XML endpoints, you might return JSON errors
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
}
}
}
}
)
async def get_single_product_xml(item_id: str):
"""
Retrieves details for a specific product ID and returns the information
in a structured XML format. The documentation will show an example XML payload.
"""
if item_id == "PROD-001":
product_data = ProductItem(
item_id=item_id,
name="Wireless Headphones",
description="High-fidelity audio experience.",
price=199.99,
currency="EUR"
)
return product_data.model_dump_xml()
else:
# FastAPI will handle 404 response default
return Response(content="<error><message>Product not found</message></error>", status_code=404, media_type="application/xml")
@app.get(
"/techblog/en/products/catalog-xml",
response_class=XMLResponse,
summary="Get product catalog as XML",
responses={
200: {
"description": "Full product catalog retrieved in XML format.",
"content": {
"application/xml": {
"schema": {
"type": "string",
"format": "xml",
"example": SAMPLE_XML_CATALOG
}
}
}
}
}
)
async def get_product_catalog_xml():
"""
Returns a comprehensive catalog of products in XML format.
This demonstrates documenting a more complex XML structure.
"""
catalog_data = ProductCatalog(
products=[
ProductItem(
item_id="PROD-001",
name="Wireless Headphones",
description="High-fidelity audio experience.",
price=199.99,
currency="EUR"
),
ProductItem(
item_id="PROD-002",
name="Smartwatch X",
price=299.00,
currency="USD"
)
]
)
return catalog_data.model_dump_xml()
When you navigate to /docs with this application running, you will see for the /products/single-xml/{item_id} and /products/catalog-xml endpoints: * A "200 OK" response. * The description provided ("Successfully retrieved product details in XML format."). * A "Media Type" dropdown that explicitly lists application/xml. * When application/xml is selected, an "Example Value" box will display the SAMPLE_XML_ITEM or SAMPLE_XML_CATALOG XML, formatted and syntax-highlighted. This provides consumers with an immediate visual understanding of the expected XML structure.
Important Considerations for responses: * response_model vs. responses: When you use response_class=XMLResponse and explicitly define responses with application/xml, the response_model parameter for that particular HTTP status code (e.g., 200) is implicitly overridden or ignored for application/xml. If you still want to document application/json as an alternative response for the same status code, you would include it alongside application/xml in the content dictionary. * Error Responses: It's common for even XML-producing endpoints to return JSON-formatted error messages (e.g., for validation errors, 404 Not Found, 500 Internal Server Error) as defined by FastAPI's default exception handlers. In such cases, you should explicitly document these JSON error responses within your responses dictionary as well, like the 404 example above.
Solution 2: Customizing FastAPI's OpenAPI Generation (Advanced)
For highly dynamic or more generalized scenarios, you might want to programmatically modify the OpenAPI specification itself. FastAPI provides access to the raw OpenAPI JSON via app.openapi(). You can modify this dictionary before it's served. This approach is more complex and generally only necessary if the responses decorator doesn't offer enough flexibility or if you need to apply a consistent XML documentation pattern across many endpoints without repetitive decorator entries.
Here's a conceptual outline of how you might achieve this:
from fastapi import FastAPI, Response
from fastapi.openapi.utils import get_openapi
from copy import deepcopy
app = FastAPI(
title="Custom OpenAPI XML Example",
description="Demonstrates advanced OpenAPI customization for XML responses."
)
class XMLResponse(Response):
media_type = "application/xml"
# Example XML content
XML_DATA = """<?xml version="1.0" encoding="UTF-8"?>
<data><status>success</status><message>Custom OpenAPI example worked!</message></data>"""
@app.get("/techblog/en/api/dynamic-xml", response_class=XMLResponse, summary="A dynamically documented XML endpoint")
async def get_dynamic_xml_data():
"""
This endpoint will have its XML documentation injected programmatically.
"""
return XML_DATA
# Cache the generated OpenAPI schema
_cached_openapi_schema = None
def custom_openapi():
global _cached_openapi_schema
if _cached_openapi_schema is not None:
return _cached_openapi_schema
# Generate the default OpenAPI schema
openapi_schema = get_openapi(
title=app.title,
version=app.version,
description=app.description,
routes=app.routes,
)
# Now, iterate through the paths and modify
# For demonstration, we'll target our specific endpoint
path_key = "/techblog/en/api/dynamic-xml"
if path_key in openapi_schema["paths"]:
for method in openapi_schema["paths"][path_key]: # 'get', 'post', etc.
operation = openapi_schema["paths"][path_key][method]
# Ensure responses exist and for status code 200
if "responses" not in operation:
operation["responses"] = {}
if "200" not in operation["responses"]:
operation["responses"]["200"] = {"description": "Successful Response"} # Default
# Add or update the XML content type
if "content" not in operation["responses"]["200"]:
operation["responses"]["200"]["content"] = {}
operation["responses"]["200"]["content"]["application/xml"] = {
"schema": {
"type": "string",
"format": "xml",
"example": XML_DATA # Use our example XML
}
}
# Remove any default application/json if we only expect XML
# if "application/json" in operation["responses"]["200"]["content"]:
# del operation["responses"]["200"]["content"]["application/json"]
_cached_openapi_schema = openapi_schema
return _cached_openapi_schema
# Override FastAPI's default openapi generation
app.openapi = custom_openapi
In this advanced setup, we override FastAPI's app.openapi method with our custom_openapi function. This function first generates the standard OpenAPI schema and then programmatically traverses it to inject the application/xml content type and its schema/example for the /api/dynamic-xml endpoint.
APIPark Integration Point: When dealing with a microservices architecture where some services might still expose XML, or where a blend of traditional REST APIs, GraphQL, and even AI services are in play, an API management platform becomes invaluable. Platforms like APIPark excel in unifying the management and documentation of such diverse APIs. By centralizing API lifecycle management, APIPark ensures that even complex XML response schemas are accurately reflected in a single, accessible developer portal, simplifying integration for consumers and reducing the overhead for providers. APIPark can consume OpenAPI specifications (which you've meticulously crafted to include XML details) and present them in a consistent, user-friendly manner, abstracting away the underlying complexities of different data formats. This means developers consuming your API through APIPark's portal will see clear documentation for both JSON and XML responses, irrespective of the backend implementation details.
Solution 3: Using extra_json_schema_data (Less Direct for Content Type)
While extra_json_schema_data is a parameter on Field and BaseModel that allows adding arbitrary data to the generated JSON Schema for Pydantic models, it's not the primary or most effective way to directly specify application/xml as a content type for a response. Its main purpose is to inject custom metadata or OpenAPI extensions into the schema itself, which typically describes the structure of a JSON payload.
For instance, you might use it to add a custom x-xml-root-element property to a JSON Schema if you wanted to imply that this JSON structure could be converted to XML with a specific root element. However, it doesn't directly configure the content type of an operation's response in the OpenAPI document.
If you were defining a Pydantic model that could be serialized to XML (e.g., using pydantic-xml), you might use extra_json_schema_data to add an example of the XML equivalent within the JSON Schema's example, but this is a workaround, not a direct declaration of application/xml as the response type. The responses parameter remains the canonical and most straightforward method for explicitly documenting different content types.
Example of extra_json_schema_data (for context, not the solution):
from pydantic import BaseModel, Field
class ItemWithXmlHint(BaseModel):
id: str
name: str = Field(...,
extra_json_schema_data={"x-xml-tag": "itemName", "example": "Super Widget"}
)
# This just adds metadata to the JSON schema, it doesn't declare an XML response
As you can see, this only adds metadata to the JSON schema description of name, not to the overall response content type. Therefore, for reliably documenting XML responses, stick with the responses parameter.
VI. Best Practices for Documenting XML Responses in FastAPI
Successfully configuring FastAPI to serve XML is only the first step; ensuring that this is clearly communicated through your API documentation is equally, if not more, important for API consumers. Poorly documented XML responses can be a significant source of frustration, leading to integration delays and errors. Here are some best practices to maximize clarity and utility when documenting XML responses in FastAPI:
- Always Provide Clear
descriptionandexamplefor XMLcontent: The most crucial element in documenting XML responses within OpenAPI is theexamplefield under theapplication/xmlcontenttype. A well-formatted, representative XML example immediately shows consumers what to expect. Couple this with a descriptivedescriptionto explain the purpose and context of the XML payload.- Bad Example (Missing example):
python "content": {"application/xml": {"schema": {"type": "string", "format": "xml"}}}(This is technically correct but unhelpful to a human trying to understand the structure.) - Good Example (With example):
python "content": { "application/xml": { "schema": { "type": "string", "format": "xml", "example": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><data><id>123</id><value>test</value></data>" }, "example": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><data><id>123</id><value>test</value></data>" } }Note that OpenAPI 3.0+ supportsexamplefield directly under thecontentmedia type object, allowing for multiple examples and a more direct representation than nesting it underschema'sexample. The above snippet demonstrates theexampleunderschema, which is also widely supported by Swagger UI. For multiple examples, consider using theexampleskeyword directly under the media type.
- Bad Example (Missing example):
- Use XML Schema Definitions (XSDs) for Complex XML Validation (Externally): While OpenAPI's
schemaforapplication/xmlis often just a string with an example, the real power of XML for strict validation lies in XML Schema Definitions (XSDs). If your XML payload adheres to a complex XSD, consider making this XSD accessible alongside your API documentation.- Mention the XSD in the
descriptionfield of your OpenAPI operation. - Provide a link to the XSD file itself in your API portal or supplementary documentation.
- Consider an OpenAPI Extension: For very advanced use cases, you could use an OpenAPI extension (e.g.,
x-xsd-schema-url) within yourresponsesdefinition to explicitly link to an external XSD file. This would require custom rendering in your documentation viewer, but it could be powerful.json "schema": { "type": "string", "format": "xml", "example": "...", "x-xsd-schema-url": "https://example.com/schemas/my_complex_data.xsd" }
- Mention the XSD in the
- Ensure Consistency in XML Structure: If your API returns similar XML structures across different endpoints, strive for consistency in element naming, attribute usage, and overall hierarchy. This reduces the learning curve for API consumers. Use consistent XML namespaces where applicable, and reflect these namespaces accurately in your example XML.
- Versioning XML APIs Explicitly: Just like JSON APIs, XML APIs should be versioned. This can be done via URL paths (e.g.,
/v1/data.xml), query parameters, or HTTPAcceptheaders (e.g.,Accept: application/vnd.mycompany.v1+xml). Document your versioning strategy clearly within your FastAPI application'stitle,description, and individual path operationsummaryfields. - Leverage OpenAPI
descriptionFields for Contextual Information: Beyond the XML example, use thedescriptionfields at the path operation level, response level, and even potentially within the schema if you're using a more structured XML schema representation (though less common directly in OpenAPI for XML). Explain the business context of the XML data, any specific rules, or relationships between elements that might not be immediately obvious from the XML structure itself. - Human-Readable Descriptions for XML Payload Structures: When possible, try to break down the XML payload's logical components in prose within the
description. For example, instead of just showing the XML for a "Customer" object, describe what each top-level element (e.g.,<customer>), its attributes (e.g.,id), and key child elements (e.g.,<name>,<address>) represent. This is especially helpful if your XML is verbose or has a deep nesting. - Consider Using
pydantic-xmlfor Internal Consistency: If you're building new XML-producing APIs and also using Pydantic for JSON,pydantic-xmlcan offer a powerful way to define your data models consistently. While it doesn't directly populate the OpenAPIresponsesexamplefield, it ensures that your Python code's XML output perfectly matches your internal model, making it easier to generate accurate examples for your documentation. You can thenmodel_dump_xml()from yourpydantic-xmlmodel to get the exactexamplestring to paste into yourresponsesdefinition.
By adhering to these best practices, you can transform your FastAPI application's XML documentation from a potential source of confusion into a valuable asset, making your XML-based API endpoints as discoverable and understandable as their JSON counterparts.
VII. The Broader Context: API Management and Multi-Format APIs
The journey of building a FastAPI application that intelligently handles and documents XML responses highlights a critical aspect of modern API ecosystems: the increasing complexity and diversity of API landscapes. Organizations today often manage a heterogeneous mix of APIs: traditional REST APIs (mostly JSON), legacy SOAP services (XML), modern GraphQL endpoints, gRPC services, and a rapidly expanding array of AI-powered services. This multi-format environment presents significant challenges in terms of governance, security, performance, and most pertinently for our discussion, unified documentation.
The Challenge of Mixed API Landscapes
Imagine an enterprise with: * A set of core financial services built on decades-old SOAP/XML. * New microservices developed with FastAPI, offering REST/JSON. * A newly integrated third-party AI model for sentiment analysis, potentially exposed via a custom HTTP API with specific input/output formats. * An internal data analytics platform exposing data via GraphQL.
Each of these APIs might have its own documentation format (WSDL for SOAP, OpenAPI for REST, GraphQL Schema Definition Language). Consumers integrating with this enterprise's services face a fragmented experience, needing to navigate multiple portals, understand different data serialization formats, and grapple with varying security mechanisms.
The Role of API Gateways and Management Platforms
This is precisely where API gateways and comprehensive API management platforms become indispensable. These platforms act as a central nervous system for an organization's API landscape, providing a single point of entry and management for all API traffic. Their functionalities typically include:
- Traffic Routing and Load Balancing: Directing incoming requests to the correct backend services.
- Authentication and Authorization: Enforcing security policies uniformly across all APIs, regardless of their native authentication mechanisms.
- Rate Limiting and Throttling: Protecting backend services from overload.
- Transformation: Converting data formats (e.g., XML to JSON, or vice-versa) between client and backend, allowing a legacy XML service to be exposed as a modern JSON API without rewriting the backend.
- Monitoring and Analytics: Providing insights into API usage, performance, and errors.
- Developer Portals and Documentation: Consolidating documentation for all APIs into a single, user-friendly interface.
Unifying Documentation with API Management Platforms like APIPark
For the specific challenge of documenting diverse content types like XML and JSON, an API management platform's developer portal is a game-changer. These platforms are designed to consume various API specification formats (like OpenAPI, WSDL, GraphQL SDL) and present them in a standardized, interactive manner.
Consider the scenario discussed throughout this article: a FastAPI endpoint correctly serving XML, with its application/xml response schema and examples meticulously defined in the OpenAPI specification using the responses parameter. When this FastAPI service is exposed through an API management platform like APIPark, the platform will ingest this OpenAPI specification.
APIPark's Value in a Multi-Format API World:
APIPark, as an open-source AI gateway and API management platform, is specifically designed to address these complex challenges. It unifies the management, integration, and deployment of both AI and traditional REST services. For scenarios involving diverse content types and sophisticated documentation, APIPark offers significant value:
- Unified Developer Portal: APIPark consolidates all API documentation, regardless of the underlying format (JSON, XML, or even specific AI model input/output schemas), into a single, consistent developer portal. This means API consumers only need to visit one place to discover and understand all available APIs, including those serving XML.
- Intelligent Documentation Rendering: When APIPark processes an OpenAPI specification that explicitly details
application/xmlresponses with examples (as we've learned to create in FastAPI), it will render this information clearly in its portal. Consumers will see the XML content type, alongside any JSON options, and be able to view the example XML payloads directly. - API Lifecycle Management: Beyond documentation, APIPark assists with the entire API lifecycle, from design and publication to invocation and decommissioning. This includes regulating management processes, traffic forwarding, load balancing, and versioning of published APIs. Such features are invaluable when managing a mix of new and legacy APIs.
- AI Integration: With its focus on AI gateway capabilities, APIPark can standardize the invocation format across 100+ AI models, ensuring that changes in AI models do not affect the application. This demonstrates its capability to abstract and unify diverse interfaces, a principle that extends to handling different data formats like XML and JSON for traditional APIs.
- Team Collaboration and Permissions: APIPark allows for centralized display of API services within teams and supports independent API and access permissions for each tenant, making it easier for different departments to find and use required APIs securely, regardless of the underlying data format.
By leveraging a platform like APIPark, organizations can bridge the gap between their diverse API implementations and a streamlined, secure, and well-documented API consumption experience. It ensures that the careful work put into documenting XML responses in FastAPI translates into immediate clarity for every API consumer accessing the central developer portal, ultimately enhancing efficiency, security, and data optimization for all stakeholders.
VIII. Conclusion
In the evolving landscape of API development, while JSON has become the ubiquitous language of data interchange, the necessity to produce and consume XML remains a reality for many applications, especially those integrating with legacy systems, adhering to industry standards, or dealing with document-centric data. FastAPI, with its unparalleled speed, elegant design, and powerful automatic documentation features, empowers developers to build high-performance APIs that can cater to both JSON and XML requirements.
The core insight we've uncovered is that while FastAPI excels at automatically documenting JSON responses via Pydantic models, explicitly informing its OpenAPI documentation about XML responses requires a targeted approach. We explored various methods for crafting XML responses using Python's native xml.etree.ElementTree, the highly performant lxml library, and the modern pydantic-xml library, which elegantly bridges Pydantic's validation with XML serialization.
Crucially, we delved into the primary method for making these XML responses visible and understandable within the generated OpenAPI documentation: the responses parameter in FastAPI's path operation decorators. By explicitly defining the application/xml content type, along with a descriptive schema and, most importantly, a clear example of the XML payload, developers can transform potentially ambiguous documentation into an invaluable resource for API consumers. For advanced scenarios, direct manipulation of the OpenAPI schema via app.openapi() provides ultimate control, though it requires a deeper understanding of the OpenAPI specification.
Adhering to best practices such as providing detailed examples, considering external XSDs, ensuring structural consistency, and leveraging description fields are paramount for creating truly effective documentation for XML-based endpoints.
Ultimately, a well-documented API, irrespective of its underlying content type, is a hallmark of a robust and developer-friendly service. By mastering these techniques in FastAPI, you not only enhance the clarity and usability of your API for consumers but also ensure that your powerful backend services are fully understood and adopted, whether they speak the language of JSON, XML, or a combination thereof, further complemented by sophisticated API management solutions like APIPark.
IX. FAQs
1. Why does FastAPI default to JSON documentation even when I return XML? FastAPI leverages Pydantic models, which are inherently designed for JSON serialization and validation. When Pydantic models are used as response_model, FastAPI automatically translates them into JSON Schema for the OpenAPI documentation, assuming application/json as the content type. When you return a custom XMLResponse or Response with media_type="application/xml", FastAPI correctly sets the HTTP header for the actual response, but this explicit media_type information doesn't automatically translate into a corresponding application/xml entry in the OpenAPI specification's content section without your explicit instruction.
2. What is the most straightforward way to document XML responses in FastAPI's OpenAPI docs? The most straightforward and recommended method is to use the responses parameter within your FastAPI path operation decorator (e.g., @app.get). Within this parameter, you define a dictionary where status codes map to response descriptions. For the desired status code, specify the application/xml media type under the content key, and crucially, include an example of the XML payload within its schema or directly under the media type object. This example will be rendered in Swagger UI/ReDoc, clearly showing API consumers the expected XML structure.
3. Can I use Pydantic models to define XML structures for documentation and serialization? Yes, you can! Libraries like pydantic-xml allow you to define XML structures using familiar Pydantic syntax. While pydantic-xml models don't directly integrate into FastAPI's response_model for XML schema generation in OpenAPI (as response_model is JSON-centric), they are incredibly useful for two things: a. Programmatically generating XML content from Python objects. b. Providing a canonical, validated structure from which you can derive your example XML string to include in the responses parameter for documentation.
4. What if my FastAPI endpoint returns both JSON and XML depending on the Accept header? How do I document that? You can document multiple content types for the same HTTP status code within the responses parameter. For instance, for a 200 OK response, you would specify both application/json and application/xml under the content key, each with its respective schema and example. Your FastAPI endpoint logic would then need to inspect the client's Accept header to dynamically determine which content type to return. FastAPI will automatically include application/json if response_model is used, so you only need to add application/xml explicitly.
5. How does API management platform like APIPark help with documenting diverse API formats, including XML? API management platforms like APIPark provide a unified developer portal that centralizes documentation for all APIs, regardless of their underlying format (JSON, XML, GraphQL, etc.). When your FastAPI application generates an OpenAPI specification that meticulously details XML responses (using the responses parameter as discussed), APIPark ingests this specification. It then presents this information clearly in its portal, allowing API consumers to see application/xml as an available response content type, alongside any JSON options, and view the example XML payloads. This consolidates API discovery and understanding, making it easier for developers to integrate with diverse services from a single, consistent interface.
πYou can securely and efficiently call the OpenAI API on APIPark in just two steps:
Step 1: Deploy the APIPark AI gateway in 5 minutes.
APIPark is developed based on Golang, offering strong product performance and low development and maintenance costs. You can deploy APIPark with a single command line.
curl -sSO https://download.apipark.com/install/quick-start.sh; bash quick-start.sh

In my experience, you can see the successful deployment interface within 5 to 10 minutes. Then, you can log in to APIPark using your account.

Step 2: Call the OpenAI API.
