Skip to content

3. Custom Response - HTML, Stream, File, others


1. Custom Response - HTML, Stream, File, others

  • 기본적으로 FastAPIsms JSONResponse를 사용하여 response를 반환한다.
  • 직접 Response 반환에 표시된 대로 Response를 직접 반환하여 이를 오버라이드할 수 있다.
  • 그러나 Response를 직접 반환하면, 데이터가 자동으로 변환되지 않으며 문서가 자동으로 생성되지 않는다.
  • 하지만 path operation 데코레이터에 사용하려는 Response를 선언할 수 있는데, path operation function에서 반환하는 내용은 해당 Response 내부에 들어간다.
  • 그리고 JSONResponseUJSONResponse와 같이 해당 Response에 JSON 미디어 타입(application/json)이 있는 경우, 반환되는 데이터는 path operation 데코레이터에서 선언한 Pydantic response_model로 자동 변환된다.


2. Use ORJSONResponse

  • 만약 성능에 초점을 두고 있다면 orjson을 설치하여 사용하고, response를 ORJSONResponse로 설정할 수 있다.


  • 다음과 같이 사용하려는 Response 클래스를 가져와서 path operation 데코레이터에 선언한다.


from fastapi import FastAPI
from fastapi.responses import ORJSONResponse

app = FastAPI()

@app.get("/items/", response_class=ORJSONResponse)
async def resd_items():
    return [{"item_id": "Foo"}]


3. HTML Reseponse

  • FastAPI에서 HTML response를 반환하려면, 다음과 같이 HTMLResponse를 사용한다.


1] HTMLResponse를 임포트한다.

2] path operation 데코레이터의 매개변수 response_classHTMLResponse를 전달한다.


from fastapi import FastAPI
from fastapi.responses import HTMLResponse

app = FastAPI()

@app.get("/items/", response_class=HTMLResponse)
async def read_items():
    return """
    <html>
        <head>
            <title>Some HTML in here</title>
        </head>
        <body>
            <h1>Look ma! HTML!</h1>
        </body>
    </html>
    """


1) Return a Response

  • path operation에서 reponse를 반환하는 것으로 직접 오버라이드할 수 있다.


  • 다음과 같이 HTMLResponse를 반환할 수 있다.


from fastapi import FastAPI
from fastapi.responses import HTMLResponse

app = FastAPI()

@app.get("/items/")
async def read_items():
    html_content = """
    <html>
        <head>
            <title>Some HTML in here</title>
        </head>
        <body>
            <h1>Look ma! HTML!</h1>
        </body>
    </html>
    """

    return HTMLResponse(content=html_content, status_code=200)


2) Document in OpenAPI and override Response

  • 함수 내부에서 응답을 재정의하지만 동시에 OpenAPI에서 "media type"을 문서화하려는 경우, 매개변수 response_class를 사용하고 Response 객체를 반환할 수 있다.
  • response_class는 OpenAPI path operation을 문서화하는 데만 사용되지만 Response는 있는 그대로 사용된다.


from fastapi import FastAPI
from fastapi.responses import HTMLResponse

app = FastAPI()

def generate_html_response():
    html_content = """
    <html>
        <head>
            <title>Some HTML in here</title>
        </head>
        <body>
            <h1>Look ma! HTML!</h1>
        </body>
    </html>
    """

    return HTMLResponse(content=html_content, status_code=200)

@app.get("/items/", response_class=HTMLResponse)
async def read_items():
    return generate_html_response()


  • 위의 예제에서 함수 generate_html_response()는 HTML을 반환하는 대신 Response를 생성하고 반환한다.
  • response_class에서도 HTMLResponse를 전달했기 때문에 FastAPI는 OpenAPI에서 문서화하는 방법을 알게 된다.


001


4. Available responses

1) Response

  • 기본 Response 클래스이며, 다른 모든 responses는 이 클래스에서 상속된다.
  • 다음과 같은 매개변수를 허용한다.


1] content

  • str 타입 또는 bytes 타입

2] status_code

  • int 타입으로 HTTP 상태 코드이다.

3] headers

  • 문자열 dict 타입

4] media_type

  • media type을 제공하는 str 타입


from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/legacy/")
def get_legacy_data():
    data = """<?xml version="1.0"?>
    <shampoo>
    <Header>
        Apply shampoo here.
    </Header>
    <Body>
        You'll have to use soap here.
    </Body>
    </shampoo>
    """

    return Response(content=data, media_type="application/xml")


2) HTMLResponse

  • 일부 텍스트 또는 bytes를 가져와 HTML response를 반환한다.


3) PlainTextResponse

  • 일부 텍스트 또는 bytes를 가져와 일반 텍스트 response를 반환한다.


from fastapi import FastAPI
from fastapi.responses import PlainTextResponse

app = FastAPI()

@app.get("/", response_class=PlainTextResponse)
async def main():
    return "Hello World"


4) JSONResponse

  • 일부 데이터를 가져와 application/json으로 인코딩된 response를 반환한다.


5) ORJSONResponse

  • orjson을 사용하여 JSON response를 반환한다.


6) UJSONResponse

  • ujson을 사용하여 JSON response를 반환한다.


from fastapi import FastAPI
from fastapi.responses import UJSONResponse

app = FastAPI()

@app.get("/items/", response_class=UJSONResponse)
async def read_items():
    return [{"item_id": "Foo"}]


7) RedirectResponse

  • HTTP 리디렉션을 반환한다.
  • 기본적으로 307 상태 코드를 사용한다.


from fastapi import FastAPI
from fastapi.responses import RedirectResponse

app = FastAPI()

@app.get("/typer")
async def redirect_typer():
    return RedirectResponse("https://typer.tiangolo.com")


  • 또는 다음과 같이 파라미터 response_class를 사용할 수 있다.


from fastapi import FastAPI
from fastapi.responses import RedirectResponse

app = FastAPI()

@app.get("/fastapi", response_class=RedirectResponse)
async def redirect_fastapi():
    return "https://fastapi.tiangolo.com"


8) StreamingResponse

  • async generator 또는 일반적인 generator/iterator를 사용하여 response body를 스트림한다.


from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()

async def fake_video_streamer():
    for i in range(10):
        yield b"some fake video bytes"

@app.get("/")
async def main():
    return StreamingResponse(fake_video_streamer())


  • 만약 open()에 의해 반환된 객체인 file-like 객체가 있는 경우, 해당 file-like 객체를 반복하는 generator 함수를 생성할 수 있다.
  • 이런 방식을 이용하면, 메모리에서 모든 것을 읽을 필요가 없이 해당 generator 함수를 StreamingResponse에 전달하고 반환할 수 있다.


from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()

some_file_path = "large-video-file.mp4"

@app.get("/")
def main():
    def iterfile():
        with open(some_file_path, mode="rb") as file_like:
            yield from file_like

    return StreamingResponse(iterfile(), media_type="viedo/mp4")


9) FileResponse

  • 비동기식으로 파일을 response로 스트림한다.
  • 다음과 같은 인수를 사용하여 인스턴스화한다.


1] path

  • 스트림할 파일의 경로이다.

2] headers

  • dict 타입의 사용자 정의 headers이다.

3] media_type

  • media type을 제공하는 문자열이다.

4] filename

  • 설정하면 response Content-Disposition에 포함된다.


  • 또한 다음과 같이 적절한 Content-Length, Last-ModifiedETag headers가 포함된다.


from fastapi import FastAPI
from fastapi.responses import FileResponse

app = FastAPI()

some_file_path = "large-video-file.mp4"

@app.get("/")
async def main():
    return FileResponse(some_file_path)


  • 매개변수 response_class도 사용할 수 있다.


from fastapi import FastAPI
from fastapi.responses import FileResponse

app = FastAPI()

some_file_path = "large-video-file.mp4"

@app.get("/", response_class=FileResponse)
async def main():
    return some_file_path


5. Default response class

  • FastAPI 클래스 인스턴스 또는 APIRouter를 생성할 때 기본적으로 사용할 response 클래스를 지정할 수 있다.
  • 이를 정의하는 매개변수는 default_response_class이다.


  • 다음과 같이 코드를 작성하면, FastAPI는 기본적으로 모든 path operations에서 JSONResponse 대신 ORJSONResponse를 사용하게 된다.


from fastapi import FastAPI
from fastapi.responses import ORJSONResponse

app = FastAPI(default_response_class=ORJSONResponse)

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

References