프레임워크/FastAPI

[FastAPI] FastAPI [8] Body - Nested Models

:) :) 2023. 3. 28. 15:23

https://fastapi.tiangolo.com/tutorial/body-nested-models/

 

Body - Nested Models - FastAPI

Body - Nested Models With FastAPI, you can define, validate, document, and use arbitrarily deeply nested models (thanks to Pydantic). List fields You can define an attribute to be a subtype. For example, a Python list: This will make tags be a list, althou

fastapi.tiangolo.com

<FastAPI 공식문서 참조>

 

* FastAPI를 통해 임의의 깊은중첩모델을 정의, 검증, 문서화할 수 있다(Pydantic 덕분에).

 

1. List fields

 파이썬 List와 같이,  한 속성을 subtype으로 정의할 수 있다.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list = []


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

tags가 list 자료형 list로 정의되어 있다(내부 요소의 자료형은 선언하지 않았다).

 

 

1-1. List fields with type parameter

 파이썬은 list 요소의 내부 자료형 혹은 내부 자료 매개변수를 지정할 수 있는 구체적인 방법이 있다.

 

1-1-1. Import  List  from typing

 python 3.10+ 에선 아래와 같이 내부 자료형을 구체적으로 선언할 수 있다.

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list[str] = []

tags는 list 자료형이며, 내부는 string이어야 한다.

 

 

1-2. Set types

 그런데 tag의 의미를 잘 생각해보면, tag는 고유한 목록을 가지고 있어야 하므로 집합 자료형을 쓸 필요가 있다. 따라서 list보단 set을 사용해보자.

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: set[str] = set()

중복된 data를 받더라도 고유한 item으로 전환해 주는 자료형이다.

그리고 이건 주석이 될 수도, 문서가 될 수도 있다.

 

2. Nested Models

 각각의 Pydantic model의 요소는 자료형을 가지고 있다. 

그러나 그 자료형은 다른 Pydantic model이 될 수도 있다.

그래서 구체적인 유형의 이름, 자료형, 검증을 포함해 깊이 중첩된 JSON "객체"를 선언 할 수 있다.

이 모든 것은 임의적으로 중첩되있다.

 

2-1. Define a submodel

 예시로,  Image  라는 model을 정의해보자.

class Image(BaseModel):
    url: str
    name: str

 

2-2. Use the submodel as a type

 그리고 이를 요소의 자료형으로써 사용할 수 있다.

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: set[str] = set()
    image: Image | None = None

 Item의 attribute 중 하나인 image로 들어갔다.

 

 

그리고, FastAPI는 이에 해당하는 Item이라는 body를 아래와 같이 예상한다.

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": ["rock", "metal", "bar"],
    "image": {
        "url": "http://example.com/baz.jpg",
        "name": "The Foo live"
    }
}

 

이러한 선언을 하는 FastAPI를 통해,

  • Editor support( 코드 완성 등등 )(중첩 모델이어도)
  • 데이터 변환
  • 데이터 검증
  • 자동 문서화

의 기능을 얻을 수 있다.

 

 

2-3. Special types and validation

 정수형, 문자형, 실수형과 같은 표준 자료형 외에도 Pydatic에는 불러올 수 있는 다향한 외부 자료형이 존재한다. 

  • HttpUrl
    • URL인지 아닌지 검정해준다.
  • list
    • 리스트 자료형
  • set
    • 집합 자료형

등등이 있다.

 

아래는 HttpUrl 자료형에 대한 예제이다.

class Image(BaseModel):
    url: HttpUrl
    name: str

 

또한 Image model 자체를 list자료형의 인자로 받아 여러 model을 담게 선언할 수 도 있다.

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: set[str] = set()
    images: list[Image] | None = None

이때, FastAPI는 아래처럼 JSON body를 예상한다.

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": [
        "rock",
        "metal",
        "bar"
    ],
    "images": [
        {
            "url": "http://example.com/baz.jpg",
            "name": "The Foo live"
        },
        {
            "url": "http://example.com/dave.jpg",
            "name": "The Baz"
        }
    ]
}

 

 

 

3. Deeply nested models

 아래처럼 임의적으로, 깊이 중첩시킨 모델을 선언할 수 도 있다.

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: set[str] = set()
    images: list[Image] | None = None


class Offer(BaseModel):
    name: str
    description: str | None = None
    price: float
    items: list[Item]


@app.post("/offers/")
async def create_offer(offer: Offer):
    return offer

 * Offer 속 Item, 그 속 Image가 있고, 각각 list자료형으로 받고 있음을 보자.

 

 

 

 

4. Bodies of pure lists

 그냥 JSON  array ( 혹은 Python  list  )가 가장 상위 수준에서 받는 JSON body 요소라면, 아래처럼 함수의 파라미터 타입을 선언하면 된다(Pydantic 모델에서 선언하는 것 처럼).

 

(*Python 3.9+ 기준.)

images: list[Image]

아래처럼 사용한다.

class Image(BaseModel):
    url: HttpUrl
    name: str


@app.post("/images/multiple/")
async def create_multiple_images(images: list[Image]):
    return images

 

 

5. Bodies of arbitrary  dict s

 딕셔너리 자료형 또한 Body에 선언할 수 있다.

유효한 필드의 속성이 뭔지 알기 어려울 때(알 필요가 없을 때) 유용하게 사용할 수 있다.

 

다른 유용한 케이스로, 자료형을 미리 지정해서 자료형 검증을 할 수 있게 하는 것이다.

아래 예시로는 딕셔너리가 int형 키 / float형 값을 가져야 하는 검증과정을 거치게 선언하는 예제이다.

@app.post("/index-weights/")
async def create_index_weights(weights: dict[int, float]):
    return weights

* JSON은 오직 str을 키로 가지는 것을 지원한다는 것을 명심하자.

그런데 Pydantic이 자동 데이터 형변환을 지원해 줄 것이다. int로 받아도 JSON으로 넘겨줄 땐 string으로 변환해 넘겨준다.

 

 

6. Recap

 FastAPI는, 코드를 간결하고, 짧고, 우아하게 작성하면서도, Pydantic models를 통해 제공된 최대의 유동성을 가질 수 있다.

물론 다음과 같은 이점과 함께 :

  • Editor support
  • 데이터 형변환
  • 데이터 검증
  • 스키마 문서화
  • 자동 문서

 

7. Reference

https://fastapi.tiangolo.com/ko/tutorial/body-nested-models/#__tabbed_2_1

 

Body - Nested Models - FastAPI

Body - Nested Models Warning The current page still doesn't have a translation for this language. But you can help translating it: Contributing. With FastAPI, you can define, validate, document, and use arbitrarily deeply nested models (thanks to Pydantic)

fastapi.tiangolo.com