Fast API, REST API Path Parameter 설정

Junha Kim·2021년 1월 3일
2

FastAPI

목록 보기
4/16

Fast API 에서는 Flask에서 하던 것과 같이 Path Parameter를 설정할 수 있다.

from fastapi import FastAPI

app = FastAPI()

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

위와 같이 선언을 하고 난 뒤, http://127.0.0.1:8000/items/item1 으로 url을 입력해보면 {"item_id":"item1"}과 같은 결과를 얻을 수 있다.


Path Parameter with types

Fast API의 장점인 Type Hinting을 사용하여 위의 코드를 바꿔보자

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 자료형으로 Parsing이 되며, 아까와 같이 item1이라는 값을 넘기면 error log를 보여준다.

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

http://127.0.0.1:8000/items/1 로 url를 다시 요청을 보내면 {"item_id":1}과 같은 결과를 return 한다.


Order Matters

path를 정의할 때, 순서가 중요하다.

만약 /users/me 요청을 보낸다고 가정해보자. 그런데 /users/{user_id}의 path또한 있을 때, 정의된 순서에 따라 return 되는 결과 값이 달라진다.

@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}

위와 같은 순서로 정의가 되어있다면, read_user_me를 먼저 마주치기에 {"user_id": "the current user"} 의 결과가 return된다.

만약 read_user path가 먼저 위에 정의가 되어있었다면, {"user_id": "me"}의 결과가 return 된다.


Predefined values

path parameter로 들어오는 값이 정해진 범위 내에 있을 때, **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 == 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"}

Enum클래스와 str클래스를 상속받은 ModelName 클래스를 정의했다. str클래스를 상속받아서 내부 클래스 변수들은 string형식이여야 한다는 것을 명시했다.

docs에서 보면 가능한 값들이 이미 정의되어 있기 때문에 아래와 같이 select box 형태로 정해진 값만 넣을 수 있도록 설계된다.

get_model 함수의 parameter로 model_name이 들어오는데 이 파라미터의 자료형은 위에서 정의한 ModelName이다. 이 말은 model/model_name에서 넘어온 값이 ModelName객체로 자동 Parsing이 된다는 것이다. model_name을 출력해보면 Model.alexnet(resnet/lenet)과 같이 출력이 된다.

또한, ModelNameEnum 객체이기 때문에, model_name.value == "lenet" 과 같이 ModelName.value로 직접 string 값을 얻을 수 있다.

만약 ModelName에 정의되지 않은 값이 들어왔을 경우, error를 return한다.

{
   "detail":[
      {
         "loc":[
            "path",
            "model_name"
         ],
         "msg":"value is not a valid enumeration member; permitted: 'alexnet', 'resnet', 'lenet'",
         "type":"type_error.enum",
         "ctx":{
            "enum_values":[
               "alexnet",
               "resnet",
               "lenet"
            ]
         }
      }
   ]
}

정상적인 값이 들어왔을 경우, model_nameModelName객체로 반환이 되고, return이 되면서 model_name은 다시 JSON Parsing이 가능한 String객체로 변환이 된다.

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

Path Parameters Containing Paths

파일을 원할 때, 파일 경로를 path parameter로 넘겨주어야할 때가 있다.

만약 API path가 /files/{file_path}이고 file_path가 home/johndoe/myfile.txt 라고 해보자.

그렇게 되면 Full path는 /files/home/johndoe/myfile.txt이 된다.

원래 OpenAPI에서는 path parameter 안에 path가 들어가는 것은 지원하지 않았다고 한다. 하지만 Fast API는 Starlette 덕분에 이 기능이 가능하다.

해당 기능을 사용하려면 path를 아래와 같이 정의해야된다.

/files/{file_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}

file_path가 슬래쉬를 포함해도 앞에 슬래쉬를 써줘야한다. 이 경우 전체 URL은

/files//home/johndoe/myfile.txt이 될 것이다.


요약

FastAPI를 사용하면 짧고 직관적인 표준 Python 유형 선언을 사용하여 다음과 같은 이점을 얻을 수 있다.

  • Editor support: 오류 검사, 자동 완성 등
  • 데이터 "Parsing"
  • 데이터 유효성 검사
  • API 주석 및 자동 documentation

0개의 댓글