지난 번에 API Router 를 만들고 태그를 추가하고 prefix 를 추가해서 Router 에 대해서 알아보았다.
이번에는 API 에서 사용하기 위한 경로 매개변수에 대해서 알아보려고 한다.
FastAPI 공식 사이트에서도 확인할 수 있다.
경로 매개변수 - FastAPI
FastAPI framework, high performance, easy to learn, fast to code, ready for production
fastapi.tiangolo.com
그럼 직접 사용해 보면서 하나씩 알아보자.
경로 매개변수를 가지는 API 만들어보기
경로 매개변수의 경우 지난 Router 를 만들고 API 를 만드는 과정에서 사용해본 적이 있다.
@router.get("/user/{id}")
async def get_users(id):
if id == "1":
return {
"name": "jaynam",
"position": "data engineer",
}
else:
return {"message": "Not found user from id"}
이렇게 API Path 에 변수를 추가해주는 방법을 경로 매개변수라고 한다.
OpenAPI 의 문서를 확인해보면 보다 이해하기 쉽게 알아볼 수 있다.
id 라고 하는 이름을 가지는 매개변수가 있고 아래에 보면 any 와 (path) 를 볼 수 있듯이 경로 매개변수라는 것을 알 수 있다.
실제 API 를 호출하게 되면 다음과 같이 경로가 정해지는 것을 볼 수 있다.
http://localhost:8000/users/1
경로 매개변수 타입 선언하기
매개변수에 타입을 선언할 수 있는데 아무런 타입을 선언하지 않게 되면 위에서 보는 것과 같이 any 타입으로 자동으로 선언되어있는 것을 확인할 수 있다. 이때 id 값을 내가 원하는 타입으로 선언해줄 수 있는데 다음과 같이 타입을 선언해준다.
async def get_users(id: int):
변경된 코드를 보면 id 옆에 : int 가 추가된 것을 볼 수 있다.
기본적으로 파이썬에서는 타입을 선언하지 않고 사용한다. 그럼 파이썬 언어 자체적으로 타입을 선언해서 사용하게 되는데 아무런 타입을 선언하지 않아도 알아서 선언하는 장점이 있겠지만 내가 원하는 타입으로 선언된다는 보장이 없다는 단점이 존재한다.
그래서 직접적으로 타입을 선언해주는 것이 예기치 못한 에러를 발생하고 원하는 결과를 예상할 수 있다.
따라서, 타입을 선언하는 방법은 변수 옆에 콜론(:) 을 입력하고 선언하고자 하는 타입을 입력한다.
그럼 아래와 같이 내가 선언한 int 형 타입으로 변경된 것을 확인할 수 있다.
타입을 선언했다면 int 형 타입이 아닌 다른 타입이 들어올 경우 에러가 발생하게 된다.
API 순서 문제
만약 다음과 같이 경로가 고정인 API 와 매개변수를 통해 경로를 가져와 사용하는 API 를 생성하게 되면 어떻게 될까?
@router.get("/user/{id}")
async def get_users(id: int):
if id == "1":
return {
"name": "jaynam",
"position": "data engineer",
}
else:
return {"message": "Not found user from id"}
@router.get("/user/me")
async def get_users():
return {
"name": "jaynam",
"position": "data engineer",
}
/user/me 라는 고정 경로를 가지는 API 를 호출하게 되었을 때 다음과 같이 에러가 발생한다.
{
"detail": [
{
"type": "int_parsing",
"loc": [
"path",
"id"
],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "me"
}
]
}
그 이유는 경로는 순차적으로 실행되기 때문에 위에서부터 차례대로 API 를 실행하게 된다. 따라서 정상적으로 실행하기 위해서는 고정 경로를 위에 작성해주어야 한다.
@router.get("/user/me")
async def get_users():
return {
"name": "jaynam",
"position": "data engineer",
}
@router.get("/user/{id}")
async def get_users(id: int):
if id == "1":
return {
"name": "jaynam",
"position": "data engineer",
}
else:
return {"message": "Not found user from id"}
이렇게 순서를 변경하고 실행하면 에러가 발생하지 않고 정상적으로 나오는 것을 확인할 수 있다.
경로 매개변수 사전정의
매개변수를 통해 경로를 입력받아 사용할 수 있지만 내가 원하는 경로를 미리 정의하고 싶다면 파이썬 표준인 Enum 을 사용할 수 있다.
먼저, Enum 클래스를 생성한다.
Enum 클래스의 경우 API Router 의 상단에 정의할 수 있지만 나는 스키마라는 폴더를 만들어서 사용하려고 한다.
├── README.md
├── app
│ ├── main.py
│ ├── routers
│ │ └── users.py
│ └── schemas
│ └── user_schema.py
└── requirements.txt
간단하게 예제를 만들어보았다.
from enum import Enum
class UserInfoType(str, Enum):
name = "name"
position = "position"
from app.schemas.user_schema import UserInfoType
@router.get("/user/info/{type}")
async def get_user_info(type: UserInfoType):
if type == "name":
return {
"type": type,
"name": "jaynam",
}
if type == "position":
return {
"type": type,
"position": "data engineer",
}
사용자 정보를 가져오기 위한 타입을 Enum 클래스로 생성하고 Enum 클래스를 API Router 에서 가져와 매개변수의 타입으로 선언해주었다. OpenAPI 를 통해서 확인해보자.
Enum 클래스로 선언한 매개변수가 드롭다운 형태로 지정한 값만 입력할 수 있도록 만들어졌다.
이렇게 간단하게 경로 매개변수에 대해서 알아보고 정리해보았는데 더 나아가 요구사항에 맞게 어떤 경우에 경로 매개변수를 사용하는가에 대해서 알아보고 사용해본다면 잘 사용할 수 있을 것 같다.