django 웹 어플리케이션을 구성할 때, API 를 쉽게 개발하기 위해서 DRF(Django RESTful Framework)를 사용합니다. django + DRF 를 백엔드 API 서버로만 사용하기 위해 단독 구성할 수도 있지만, django 는 기본적으로 풀스택 프레임워크입니다.
웹 페이지를 렌더링하기 위한 일반적인 뷰와, API 를 개발하기 위한 API 뷰를 같이 개발할 경우에 대해서 생각해봅시다.
Django 에는 app 이라는 단위로, 기능을 분리해서 구성하게 됩니다.. Domain Driven Development과 비슷한 맥락을 갖고 있습니다. 가독성과 유지보수성 측면에도 강점이 있고, 이 app 만 따로 배포해서 사용하는 것도 가능합니다.
다음과 같은 사례를 생각해봅시다.
/mysite/ # root app
/app-a/
/app-b/
manage.py
...
# /mysite/urls.py
urlpatterns = [
path('app-a/', include('api-a', include('app-a.urls')),
path('app-b/', include('api-b', include('app-b.urls')),
...
]
api 를 app 들 내부에 작성할 경우, url pattern는 다음과 같을 것입니다.
[
<!-- 일반적인 웹 페이지들 -->
"app-a-index" : "/app-a/",
"app-b-index" : "/app-b/",
<!-- DRF는 Browsable API 를 제공한다. -->
"app-a-api-root" : "/app-a/api/",
"app-a-api-some-api" : "/app-a/api/some-api/",
"app-b-api-root" : "/app-b/api/",
"app-b-api-some-api" : "/app-b/api/some-api/",
]
이제 api-root 들로 접근하기 위한 api-root 를 추가해주겠습니다. DRF가 browsable api 를 제공하니만큼, api 를 탐색할 수 있도록 만들어주는 것입니다. 이 글에서 다뤘습니다.
[
"app-a-index" : "/app-a/",
"app-b-index" : "/app-b/",
<!-- api root 는 app-a, app-b 어느 쪽에도 속하지 않기 때문에 mysite 에 직접 작성할 수 밖에 없다. -->
"api-root" : "/api/",
"app-a-api-root" : "/app-a/api/",
"app-a-api-some-api" : "/app-a/api/some-api/",
"app-b-api-root" : "/app-b/api/",
"app-b-api-some-api" : "/app-b/api/some-api/",
]
api root 가 app-a-api-root 와 app-b-api-root의 상위 리소스라는 느낌을 주는데에도 불구하고, url 패턴에서는 일관성이 떨어집니다.
실제로 browsable api 에서 표시되는 내용을 살펴보겠습니다.
/api/ 로 들어가 api 목록을 받았는데, 하위의 항목들이 /api/ 로 시작하지 않고 완전히 다른 경로를 주고 있습니다.
만약, api 라는 별개 app 을 만든 뒤, 그 app 에 api 를 전부 구성하게 되면 위와 같은 문제는 사라지지만, 이번엔 도메인과 api 가 멀어지는 문제가 발생합니다. app-a,b 에 사용되는 api 를 api 라는 별개 앱에 개발하게 되면 app-a, b와 api 는 서로 의존하게 됩니다. (app-a, b가 렌더링하는 템플릿 페이지들이 api의 api를 사용할 것이기 때문에)
심지어 api는 app-a, app-b 양쪽에 의존하기 떄문에, app-a나 app-b 한 쪽만 사용하고 싶어도, 세 개의 앱을 전부 설치 해야 합니다. 좋은 구조라고 보긴 어려울 것 같습니다.
다음과 같은 방법을 생각해봤습니다.
# /mysite/urls.py
url_api_patterns = [
path('app-a/', include('app-a.urls_api')),
path('app-b/', include('app-b.urls_api')),
]
urlpatterns = [
path('app-a/', include('app-a.urls')),
path('app-b/', include('app-b.urls')),
# API views
path('api/', views.api_root, name='api-root'),
path('api/', include(url_api_patterns)),
]
이제, api url 구조를 안정적으로 유지하면서 도메인과 api 간의 거리도 정상적으로 유지할 수 있습니다.
django , DRF 를 같이 사용할 경우 어떤 식으로 URL 을 구성하는 것이 좋을지 고민해봤습니다. 컨벤션이나 베스트 프랙티스는 찾지 못했으나, app 내부에 같이 개발하거나, api app을 따로 개발하는 것이 일반적으로 보입니다. monolithic 한 어플리케이션의 경우에는 위의 형태가 괜찮아보입니다.
browsable api 가 없는 환경에서는 고민한 적이 없었던 문제입니다.
정보 감사합니다.