2023年8月3日木曜日

fastapi で XML なレスポンスを考える (ドキュメント生成編)

fastapi で XML なレスポンスを考える (ドキュメント生成編)

概要

前回まででカスタムレスポンスクラスを扱う方法を紹介しました
ただ openapi にレスポンスの XML 情報が掲載されない問題がありました
今回はその問題に対処してみます

環境

  • Python 3.11.3
  • fastapi 0.100.1
  • pydantic-xml 1.0.0

サンプルコード

  • vim ./app.py
import textwrap
from typing import Union

from fastapi import FastAPI, Response
from pydantic_xml import BaseXmlModel, element

app = FastAPI()


class User(BaseXmlModel, tag="User"):
    name: str = element(tag="Name")
    age: int = element(tag="Age")


class XmlResponse(Response):
    def __init__(self, content: Union[str, bytes], status_code: int = 200):
        super().__init__(content, status_code=status_code, media_type="application/xml")


@app.get(
    "/",
    response_class=XmlResponse,
    response_model=User,
    responses={
        200: {
            "description": "Success",
            "content": {
                "application/xml": {
                    "schema": {"$ref": "#/components/schemas/User"},
                    "example": textwrap.dedent(
                        """
                        <?xml version="1.0" encoding="UTF-8"?>
                        <User>
                          <Name>hawk</Name>
                          <Age>20</Age>
                        </User>
                    """
                    )[1:-1],
                },
                "application/json": None,
            },
        },
    },
)
def xml():
    result = User(name="hawksnowlog", age=10)
    return XmlResponse(content=result.to_xml())

解説

openapi のドキュメントの作成は responses 属性を使って行います
content 配下に application/xml を定義し更に schema と example を定義します
schema に直接 Python のクラスを指定すると ValueError: [TypeError("'ModelField' object is not iterable"), TypeError('vars() argument must have __dict__ attribute')] というエラーになるので openapi に出力された際にスキーマを参照する形式で指定します

そして example はヒアドキュメントで直接していします
ここが dict などにしていしまうとうまく XML が表示されないので注意が必要です

application/json のレスポンスはデフォルトで表示されてしまうので不要であれば None を指定します

動作確認

  • pipenv run uvicorn app:app --reload

で localhost:8000/docs にアクセスると以下のようにちゃんとレスポンスのサンプルが XML で表示されているのが確認できると思います

最後に

fastapi でXML のレスポンスを扱う場合には最終的には以下の組み合わせがいいかなと思います

  • モデルの表現 -> pydantic-xml
  • レスポンスの表現 -> Response クラスを継承して XmlResponse クラスを作成する
  • ドキュメントの表現 -> responses 属性を使って content に直接 application/xml のレスポンスを定義する

参考サイト

0 件のコメント:

コメントを投稿