경로 매개변수#

이 글은 Django Ninja 입문 가이드의 10번째 글이에요.
이전 글에서는 Django Ninja가 HTTP 요청을 어떻게 처리하는지 소개하며, Python type hints와의 긴밀한 결합을 강조했어요.
이번 글에서는 Django Ninja에서 HTTP 요청을 처리할 때 매우 흔하게 사용되는, 특히 RESTful API에서 중요한 경로 매개변수(path parameters)의 활용과 세부 사항을 살펴볼 거예요.
이 글에서 예제 프로젝트에 반영된 코드 변경 사항은 이 PR에서 확인할 수 있어요.
GitHub 예제 프로젝트#
1. Path Parameters란 무엇인가요?#
Path parameters는 URL을 구성하는 일부분으로, 웹 주소 경로(path)의 특정 위치에 자리하며 서로 다른 값(매개변수)에 따라 전달되는 내용을 결정하여 자원을 동적으로 지정하는 데 사용돼요.
전체 URL에서 path가 어디에 위치하는지 먼저 알아볼까요? (이미지 출처: 위키백과)

그림에서 볼 수 있듯이, 경로(path)는 URL의 일부이며, 더욱이 필수적인 부분이에요.
하지만 주의할 점은, path parameters는 Django나 Django Ninja 같은 프레임워크가 제공하는 하나의 "기능"일 뿐이라는 점이에요. URL 자체에 있어서 path는 그저 path일 뿐, 즉 단순한 문자열에 불과해요.
경로 매개변수 예시#
path parameters의 개념을 더 잘 이해할 수 있도록 간단한 예를 들어볼게요.
실제 요청 시 123이라는 값은 경로 매개변수를 통해 특정 글의 id를 나타내게 돼요:
쉽게 예상할 수 있듯이, 456이나 789가 전달되면 다른 결과를 얻게 될 거예요.
이로 인해 API는 유연성을 갖게 되어 다양한 자원에 대한 작업을 수행할 수 있으며, 각 자원마다 다른 라우팅을 만들 필요가 없어요. 엔드포인트와 라우팅은 모두 동일하고, 오직 "매개변수"만 달라질 뿐이죠.
2. 예제 프로젝트 변경 사항#
이제 예제 프로젝트의 코드를 살펴보며 이번 글의 내용을 설명해 드릴게요.
하지만 먼저 두 가지를 변경해야 해요.
변경 1: 1차 라우터 접두사 제거#
1차 라우터 접두사인 /posts/와 /user/를 제거하여, 뷰 함수의 router 데코레이터에 있는 경로를 더 완전하고 읽기 쉽게 만들게요.
원래는 이랬어요:
이제 이렇게 바꿀게요:
주의할 점은, 이는 교육의 편의를 높이기 위한 조치이며 실무에서는 보통 이렇게 하지 않는다는 점이에요. 그렇게 하면 모듈화된 라우팅의 장점을 잃게 되거든요.
변경 2: API 추가#
path parameters를 시연하기 위해, 이 기능을 실습할 수 있는 API가 하나 필요해요.
"단일 글 정보 가져오기" API를 추가해 볼게요.
자, 여기까지 준비되었으니 이제 path parameters에 대해 본격적으로 알아볼 수 있어요.
아래 코드들은 모두 예제 프로젝트에서 가져온 것들이에요.
3. Django Ninja에서 Path Parameters 사용하기#
Django Ninja에서 경로 매개변수를 정의하는 것은 매우 간단해요. router 데코레이터와 type hints를 통해 매개변수를 쉽게 처리하고 자동으로 타입 변환을 할 수 있어요.
"경로 매개변수가 포함된" API 정의하기#
Django Ninja에서 경로 매개변수가 포함된 API를 어떻게 정의하는지 살펴볼까요:
@router.get(path='/posts/{post_id}/')
def get_post(request: HttpRequest, post_id: int) -> Post:
post = Post.objects.get(id=post_id)
return post
예제에서 {post_id}는 경로 매개변수예요. 전체 path 문자열이 파싱(parsing)되어 get_post 함수 내부의 post_id 매개변수로 전달돼요.
Django Ninja는 함수 시그니처에 정의된 타입에 따라 자동으로 타입 변환을 진행해요.
예를 들어 뷰 함수에서 post_id: int로 지정했다면, Django Ninja는 자동으로 URL에서 온 문자열 매개변수를 int로 변환해 줘요.
즉, path parameters를 처리하는 과정은 두 가지 효과를 동시에 가져와요:
- 매개변수 타입 검증: 프론트엔드에서 전달된
post_id가 잘못된 타입일 때, 뷰 함수 내부에서 그 값을 계속 처리하려고 시도하다가 에러가 발생하는 것을 방지해요. - 뷰 함수 내부의 자동 타입 변환: 함수 내에서 직접 변환하는 수고를 덜어줘요.
4. Django 기본 Path Converters와의 호환성#
Django는 URL을 처리할 때 요청 경로를 "엄격하게 매칭"할 수 있도록 본래 "path converters" 기능을 제공해요.
매칭에 성공해야만 HTTP 요청을 특정 뷰 함수로 "포워딩"해요.
여기서 "엄격하다"는 의미는 타입이 path converter에 정의된 것과 일치해야만 매칭에 성공할 수 있다는 뜻이에요.
자주 사용되는 converters 타입에는 str, int, slug 등이 있으며, 이들은 URL 내 매개변수의 형식을 제한할 수 있어요:
<int:post_id>가 바로 path converter이며, 이는 post_id가 반드시 정수여야 함을 의미해요.
강조하고 싶은 점은 path converters의 주된 목적이 타입 변환이 아니라는 점이에요. 타입 변환은 부수적인 효과일 뿐이고, 주된 목적은 엔드포인트 경로의 "패턴 매칭(pattern matching)"을 위한 것이에요.
패턴이 맞지 않는 상황에서는 애초에 매칭 자체가 실패하므로, 당연히 타입 변환도 일어나지 않아요.
Django Ninja에서의 Path Converters#
Django Ninja에서는 이러한 기본 path converters를 여전히 사용할 수 있으며, 심지어 더욱 간소화되었어요.
router 데코레이터의 경로 문자열 안에 직접 쓰기만 하면 돼요:
앞서 언급했듯이 path converter가 있을 때 post_id가 유효한 int가 아니라면, URL 패턴 매칭이 즉시 실패해요. 요청은 뷰 함수에 진입하지 않으며, 타입 변환도 발생하지 않아요.
다른 경로들과도 매칭에 실패한다면, Django는 바로 "404 Not Found"를 반환할 거예요.

개인적으로 Django Ninja에서는 path converters의 기능이 type hints로 어느 정도 대체되었다고 생각해요. 두 가지를 동시에 사용하려면 판단 순서(path converters가 먼저 판단됨)와 두 곳에 설정된 타입이 반드시 같아야 함을 유의해야 해요.
5. 요청에 대한 기본 에러 처리#
요청 내의 경로 매개변수가 type hints로 정의된 타입과 맞지 않을 때, Django Ninja는 자동으로 상태 코드 422와 함께 에러 메시지 및 알림 내용을 포함한 HTTP 응답을 반환해요.
예를 들어, 사용자가 요청한 경로가 /posts/abc/ (post_id 매개변수에 숫자를 주지 않음)라면 다음과 같은 응답을 받게 돼요:
// http://127.0.0.1:8000/posts/abc/
{
"detail": [
{
"type": "int_parsing",
"loc": [
"path",
"post_id"
],
"msg": "Input should be a valid integer, unable to parse string as an integer"
}
]
}
이러한 자동 에러 처리 메커니즘은 API의 안정성을 높여줄 뿐만 아니라 개발자의 에러 처리 로직을 단순화해 줘요.
내장된 422 응답은 Django Ninja에서 매우 빈번하게 나타나며, 우리의 시간을 많이 절약해 준답니다.
소결 및 다음 단계#
경로 매개변수는 RESTful API에서 중요한 구성 요소예요. Django Ninja는 type hints와 자동화된 에러 처리를 통해 경로 내의 동적 매개변수를 쉽게 처리할 수 있게 해줘요.
또한 Django의 기본 path converters와 훌륭한 호환성을 유지하여 효율적이고 간결한 개발 경험을 제공해요.
다음 글에서는 쿼리 매개변수(query parameters)를 깊이 있게 살펴보고, Django Ninja에서 이를 어떻게 처리하여 API의 유연성과 기능을 더욱 향상시킬 수 있는지 알아볼게요.