Skip to content

3. Path Parameters


1. Path Parameters

  • Python 문자열 형식에서 사용하는 것과 동일한 구문으로 path "매개변수" 또는 "변수"를 선언할 수 있다.


from fastapi import FastAPI

app = FastAPI()

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


  • path 매개변수 item_id의 값은 item_id 인수로, 이것은 함수에 전달된다.


  • 따라서 위의 코드를 실행하고 http://127.0.0.1:8000/items/foo로 이동하면 다음과 같은 response가 표시된다.


{
  "item_id": "foo"
}


2. Path parameters with types

  • 표준 Python 타입 어노테이션을 사용하여 함수에서 path 매개변수 타입을 선언할 수 있다.


from fastapi import FastAPI

app = FastAPI()

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


  • 위의 코드에서 볼 수 있듯이 item_idint로 선언된다.
  • 이렇게 하면 타입 및 에러를 검사하기가 편해진다.


3. Data conversion

  • 위의 코드를 실행하고 http://127.0.0.1:8000/items/3로 이동하면 다음과 같은 response가 표시된다.


{
  "item_id": 3
}


  • 함수가 수신하고 리턴한 값은 str "3"이 아니라 int 3이다.
  • 따라서 어노테이션을 통한 타입 선언으로, FastAPI의 자동 request "parsing"을 이용할 수 있다.


4. Data validation

  • 하지만 위의 코드를 실행하고 http://127.0.0.1:8000/items/foo로 이동하면 다음과 같은 HTTP 에러가 표시된다.


{
  "detail": [
    {
      "loc": ["path", "item_id"],
      "msg": "value is not a valid integer",
      "type": "type_error.integer"
    }
  ]
}


  • 에러가 표시된 이유는 path 매개변수 item_idint가 아닌 "foo" 값이 있기 때문이다.


  • 또한 다음과 같이 http://127.0.0.1:8000/items/4.2로 이동하면 동일한 HTTP 에러가 표시된다.


{
  "detail": [
    {
      "loc": ["path", "item_id"],
      "msg": "value is not a valid integer",
      "type": "type_error.integer"
    }
  ]
}


  • 위와 같이 Python 타입 선언을 통해 FastAPI는 데이터 유효성 검사를 제공한다.
  • 에러에는 유효성 검사가 통과하지 못한 지점도 명확하게 명시되어 있다.
  • 이는 API와 상호 작용하는 코드를 개발하고 디버깅하는 데 유용하다.


5. Documentation

  • 다음과 같이 http://127.0.0.1:8000/docs로 이동하면 자동 대화형 API 문서가 표시된다.


001


6. Pydantic

  • 모든 데이터 유효성 검사는 Pydantic에 의해 내부적으로 수행된다.
  • str, float, bool 및 기타 여러 복합 데이터 타입과 같은 타입 선언을 사용할 수 있다.


7. Order matters

  • path operation을 생성할 때, 고정 path가 있는 상황이 발생할 수 있다.
  • 예를 들어, /users/me와 같은 고정 path를 사용하여 현재 사용자에 대한 데이터를 가져오면서 /users/{user_id}와 같은 path를 사용하여 일부 사용자 ID로 특정 사용자에 대한 데이터를 가져올 수도 있다.
  • 이때 path operation은 순서대로 평가되므로 /users/{user_id}에 대한 path보다 /users/me에 대한 path가 먼저 선언된 것을 확인해야만 한다.


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}에 대한 path는 /users/me에 대한 path와 일치하게 되어 값이 "me"user_id 매개변수를 수신하게 된다.


8. Predefined values

  • path 매개변수를 수신하는 path operation이 있지만, 사용 가능한 유효한 path 매개변수 값을 미리 정의하려는 경우 표준 Python Enum을 사용할 수 있다.


1) Create an Enum class

  • Enum을 임포트한 후 strEnum에서 상속하는 하위 클래스를 만든다.
  • str에서 상속함으로써 API 문서는 값이 String 타입이어야 올바르게 렌더링할 수 있다는 것을 알 수 있다.
  • 그런 다음 사용 가능한 유효한 값이 될 고정 값으로 클래스 속성을 만든다.


from enum import Enum
from fastapi import FastAPI

app = FastAPI()

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

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == 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"}


2) Declare a path parameter

  • 그런 다음 ModelName이라는 enum 클래스를 타입 어노테이션으로 사용하여 path parameter를 생성한다.


from enum import Enum
from fastapi import FastAPI

app = FastAPI()

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

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == 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"}


3) Check the docs

  • path 매개변수에 사용 가능한 값이 미리 정의되어 있기 때문에 대화형 문서는 이를 보기 좋게 표시할 수 있다.


002


4) Working with Python enumerations

  • path 매개변수의 값은 열거형 멤버가 된다.


(1) Compare enumeration members

  • 생성한 enum ModelName의 열거형 멤버를 비교할 수 있다.


from enum import Enum
from fastapi import FastAPI

app = FastAPI()

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

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == 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"}


(2) Get the enumeration value

  • model_name.value를 사용하여 실제 값을 얻을 수 있다.


from enum import Enum
from fastapi import FastAPI

app = FastAPI()

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

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == 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"}


(3) Return enumeration members

  • JSON body에 중첩된 경우에도 path operation에서 enum 멤버를 반환할 수 있다.
  • 클라이언트에 반환하기 전에 해당 값으로 변환된다.


from enum import Enum
from fastapi import FastAPI

app = FastAPI()

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

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == 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 response를 받게 된다.


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


9. Path parameters containing paths

  • path가 /files/{file_path}인 path operation이 있다고 가정해 보자.
  • 이런 상황에서 home/johndoe/myfile.txt와 같은 path를 포함하려면 file_path 자체가 필요하다.
  • 따라서 해당 파일의 URL은 /files/home/johndoe/myfile.txt과 같게 된다.


1) Path convertor

  • Starlette에서 직접 옵션을 사용하면, 다음과 같은 URL을 사용하여 path가 포함된 path 매개변수를 선언할 수 있다.


/files/{file_path:path}


  • 이 경우 매개변수의 이름은 file_path이고 마지막 부분인 :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}


Note

  • 위의 예제와는 다르게, 선행 슬래시(/)가 있는 매개변수 /home/johndoe/myfile.txt가 필요한 경우가 발생할 수 있다.
  • 이런 경우 URL은 이중 슬래시(//)가 있는 /files//home/johndoe/myfile.txt와 같은 모양이 된다는 것을 유의해야 한다.

References