#59.TIL | FastAPI 공식문서 따라하기(2)

Seongjae Hwang·2023년 1월 15일
0

https://slender-danger-059.notion.site/3-Path-Parameters-c6adb1f360a44456956c4a7d462feafb

path Parameters

파이썬 기본 문법으로 매개변수를 경로에서 설정할 수 있다.

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

데코레이터에 있는 매개변수 item_id의 값은 밑에 있는 함수에 인자로 전달이 된다.

Path parameters with types

파이썬의 표준 타입 annotations을 통해 Path Parameter의 타입을 선언할 수 있다. (annotations은 python3 이상에서 사용이 가능하며 매개변수와 return값의 타입을 명시해 줄 수 있음.)

Python3 - Function annotation 에 대하여

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}

이를 통해 함수 내에서 오류 검사, 자동완성 등의 기능을 추가할 수 있음.

Data conversion

만약에 위 서버를 실행하고 http://127.0.0.1:8000/items/3를 실행하게 되면 다음과 같은 응답값을 가지게 됨.

{"item_id":3}
  • 함수가 받은 값이 문자열이 아닌 int형의 3이다. 따라서, 타입 선언을 하게 되면 FastAPI는 자동으로 파싱을 한다.

Data validation

또한, http://127.0.0.1:8000/items/abc를 실행하게 되면 데이터 타입이 맞지 않기 때문에 HTTP에러를 일으킨다.

{
    "detail": [
        {
            "loc": [
                "path",
                "item_id"
            ],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}
  • 즉, 파이썬 타입 선언만 하더라도 FastAPI는 데이터 검증을 하고, 틀린 지점까지도 명시해 준다.

Pydantic

pydantic

모든 데이터 검증은 Pydantic에 의해 수행되고 str, float, bool을 포함해서 많은 복잡한 데이터 타입을 사용할 수 있다.

순서 문제

path 파라미터를 받는 api와 고정 경로를 가지고 있는 api가 맞닦뜨리는 경우가 있다. 이와 같은 경우는 css와 같이 api도 순차적으로 위에서부터 아래로 내려온다.

ex) /users/{user_id} AND /users/me

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}

@app.get("/users/{user_id}")
async def read_user(user_id: str):
    return {"user_id": user_id}

그렇지 않으면 /users/{user_id}는 매개변수 user_id의 값을 “me”라고 생각하여 /users/me도 처리를 하게 됨.

사전정의 값

만약 path 파라미터를 받는 API가 있고, 미리 파라미터의 값을 정의하기 원한다면 파이썬의 표준 문법인 Enum을 사용할 수 있다.

Enum 클래스 생성

참고 : Enum은 파이썬 버전 3.4 이후로 사용이 가능.

Enum을 임포트하고 str과 Enum을 상속하는 서브 클래스(ModelName)를 만든다.

str을 상속함으로써 API 문서는 값이 문자열 형이어야 한느 것을 알게 되고 제대로 렌더링 할 수 있게 된다.

from enum import Enum

from fastapi import FastAPI

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

app = FastAPI()

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

실제로 적용해보고 문서를 보니, 선택할 수 있는 path 파라미터는 alexnet, resnet, lenet 이렇게 총 3가지. 이것이 API를 짜는데 있어서 엄청난 효과는 없다고 생각하지만, 협업을 하는데 있어서 문서를 확실하게 정의하는데 있어 장점이 있는것 같다.

파이썬 열거형(enumerations)으로 작업하기

The value of the path parameter will be an enumeration member.

  1. Enum멤버 비교 하기

enum 클래스인 ModelName의 enum 멤버를 비교할 수 있음.

from enum import Enum

from fastapi import FastAPI

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

app = FastAPI()

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    **if model_name is ModelName.alexnet:**
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}
  1. Enum값 들고 오기

model_name.vlaue 혹은 enum멤버이름.value를 이용하여 실제값을 가져올 수 있음.

from enum import Enum

from fastapi import FastAPI

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

app = FastAPI()

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    **if model_name.value == "lenet":**
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}
  1. enum 멤버 return

path 파라미터를 받는 API에서 enum 멤버의 값을 JSON에 중첩해서 반환할 수 있음.

from enum import Enum

from fastapi import FastAPI

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

app = FastAPI()

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name is ModelName.alexnet:
        **return {"model_name": model_name, "message": "Deep Learning FTW!"}**

    if model_name.value == "lenet":
        **return {"model_name": model_name, "message": "LeCNN all the images"}**

    **return {"model_name": model_name, "message": "Have some residuals"}**

그렇게 되면 클라이언트에서는 아래와 같은 JSON 응답값을 얻을 수 있게 된다.

{
  "model_name": "alexnet",
  "message": "Deep Learning FTW!"
}

path들을 포함하는 path 파라미터

/files/{file_path}를 받는 그러니까 file_path에서는”/home/johndoe/myfile.txt”와 같이 경로를 파라미터로 받는 API가 있다고 하면, 기존에 하던것과 같이 받게 되면 아래와 같이 에러가 나게 된다.

이와 같은 경우에는 Path convertor라는 기능을 사용할 수 있다.

Path convertor

Starlette에서 직접 옵션을 사용하여 path를 포함하는 path 파라미터인것을 알려줄 수 있다.

from fastapi import FastAPI

app = FastAPI()

**@app.get("/files/{file_path:path}")**
async def read_file(file_path: str):
    return {"file_path": file_path}

그러면 아래와 같이 정상적으로 반환값을 얻을 수 있다.

profile
Always Awake

0개의 댓글