2023年7月31日月曜日

fastapi で XML なレスポンスを考える

fastapi で XML なレスポンスを考える

概要

今回は pydantic_xml を使って fastapi で XML レスポンスを返却する方法を考えます

環境

  • Python 3.11.3
  • fastapi 0.100.1
  • pydantic-xml 1.0.0

サンプルコード

  • vim ./app.py
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")


@app.get("/", response_class=Response)
def xml():
    data = """<?xml version="1.0"?>
    <User>
      <Name>hawksnowlog</Name>
      <Age>10</Age>
    </User>
    """
    result = User.from_xml(data)
    return Response(content=result.to_xml(), media_type="application/xml")

動作確認

  • pipenv run uvicorn app:app --reload
  • curl -v localhost:8000/

=> <User><Name>hawksnowlog</Name><Age>10</Age></User>

解説

XML の構造を pydantic で扱うには pydantic_xml.BaseXmlModel を使います
各エレメントごとにクラスの属性として定義することができます
今回は単純な文字列と数字のフィールドなので element を使っています
タグ内の属性などを扱うこともできるので必要に応じて BaseXmlModel の定義を変更してください

実際にオブジェクトを作成する際は今回は文字列の XML 情報から from_xml メソッドを使って User オブジェクトを作成しています
更にそこから to_xml というシリアライズ用のメソッドが BaseXmlModel に生えているのでそれを使ってレスポンス情報を生成しています

あとは fastapi の Response クラスを使ってデータを application/xml として返却しています

最後に

pydantic-xml を使って fastapi で XML レスポンスを返却する方法を考えてみました

結局この方法だとレスポンスモデルは pydantic で管理できているが最終的なレスポンスは fastapi の Response クラスを使ってしまっているので微妙な気はします (openapi に載らないなど)

本当は response_class に XMLResponse などのクラスを定義して自動でシリアライズしてくれるような便利クラスを作成するほうがいいかなと思います (また検証次第紹介するかも)

参考サイト

0 件のコメント:

コメントを投稿