OpenAPI 확장하기

OpenAPI 확장하기 (Extending OpenAPI)

생성된 OpenAPI 스키마를 수정해야 하는 경우가 있어요. 이 섹션에서 그 방법을 볼게요.

출처: 공식문서

기본(일반적인) 과정

기본(기본값) 과정은 다음과 같아요.

FastAPI 애플리케이션(인스턴스)에는 .openapi() 메서드가 있어요. 이 메서드는 OpenAPI 스키마를 반환할 것으로 기대돼요.

애플리케이션 객체를 만들 때 /openapi.json(또는 openapi_url로 설정한 값)을 위한 경로 연산이 등록돼요.

그 경로 연산은 단지 애플리케이션의 .openapi() 메서드 결과를 JSON 응답으로 반환할 뿐이에요.

기본적으로 .openapi() 메서드는 .openapi_schema 속성을 확인해서 내용이 있으면 그걸 반환해요.

내용이 없다면 fastapi.openapi.utils.get_openapi의 유틸리티 함수를 써서 생성해요.

그리고 get_openapi() 함수는 파라미터로 이걸 받아요:

  • title: 문서에 표시되는 OpenAPI 제목이에요.
  • version: 여러분 API의 버전이에요. 예: 2.5.0.
  • openapi_version: 쓰이는 OpenAPI 명세 버전이에요. 기본값은 최신인 3.1.0이에요.
  • summary: API의 짧은 요약이에요.
  • description: 여러분 API의 설명이에요. 마크다운을 포함할 수 있고 문서에 표시돼요.
  • routes: 애플리케이션의 라우트들이에요. app.routes에서 가져와요. FastAPI는 이걸 써서 포함된 라우터들의 것을 포함해 등록된 경로 연산들을 수집해요.

기술적 세부사항app.routes는 더 저수준의 라우트 트리예요. 여기에는 FastAPI가 포함된 라우터들을 위해 내부적으로 쓰는 라우트 후보들이 들어 있을 수 있어요. 최종 APIRoute 객체만 있는 게 아니죠. 그래도 app.routesget_openapi()에 넘길 수 있어요. FastAPI가 그 라우트 트리를 순회해서 실제 경로 연산들을 수집해요.

참고summary 파라미터는 OpenAPI 3.1.0 이상에서 쓸 수 있고, FastAPI 0.99.0 이상에서 지원돼요.

기본값 오버라이드하기

위 정보를 써서 같은 유틸리티 함수로 OpenAPI 스키마를 생성하고, 필요한 각 부분을 오버라이드할 수 있어요.

예를 들어 ReDoc의 OpenAPI 확장으로 커스텀 로고를 포함시키는 걸 추가해 볼게요.

일반적인 FastAPI

먼저 FastAPI 애플리케이션을 평소대로 전부 작성해요:

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Custom title",
        version="2.5.0",
        summary="This is a very custom OpenAPI schema",
        description="Here's a longer description of the custom **OpenAPI** schema",
        routes=app.routes,
    )
    openapi_schema["info"]["x-logo"] = {
        "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    }
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

OpenAPI 스키마 생성하기

그다음 custom_openapi() 함수 안에서 같은 유틸리티 함수를 써서 OpenAPI 스키마를 생성해요:

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Custom title",
        version="2.5.0",
        summary="This is a very custom OpenAPI schema",
        description="Here's a longer description of the custom **OpenAPI** schema",
        routes=app.routes,
    )
    openapi_schema["info"]["x-logo"] = {
        "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    }
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

OpenAPI 스키마 수정하기

이제 OpenAPI 스키마의 info "객체"에 커스텀 x-logo를 추가해서 ReDoc 확장을 더할 수 있어요:

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Custom title",
        version="2.5.0",
        summary="This is a very custom OpenAPI schema",
        description="Here's a longer description of the custom **OpenAPI** schema",
        routes=app.routes,
    )
    openapi_schema["info"]["x-logo"] = {
        "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    }
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

OpenAPI 스키마 캐시하기

.openapi_schema 속성을 "캐시"로 써서 생성한 스키마를 저장할 수 있어요.

그렇게 하면 여러분 애플리케이션이 사용자가 API 문서를 열 때마다 스키마를 생성할 필요가 없어요.

딱 한 번만 생성되고, 이후 요청에는 같은 캐시된 스키마가 쓰여요.

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Custom title",
        version="2.5.0",
        summary="This is a very custom OpenAPI schema",
        description="Here's a longer description of the custom **OpenAPI** schema",
        routes=app.routes,
    )
    openapi_schema["info"]["x-logo"] = {
        "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    }
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

메서드 오버라이드하기

이제 .openapi() 메서드를 새 함수로 교체할 수 있어요.

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Custom title",
        version="2.5.0",
        summary="This is a very custom OpenAPI schema",
        description="Here's a longer description of the custom **OpenAPI** schema",
        routes=app.routes,
    )
    openapi_schema["info"]["x-logo"] = {
        "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    }
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

확인하기

http://127.0.0.1:8000/redoc로 가면 커스텀 로고(이 예시에서는 FastAPI의 로고)를 쓰고 있는 것을 볼 수 있어요.

더 알아보기 (Learn more)