본 포스팅은 아래 링크의 내용을 나름대로 정리한 글이다.
1. 모델 정의하기
소스 코드를 저장하기 위한
Snippet
모델을 정의해보자. 앞으로 계속 이 모델을 사용하여 설명할 것이다. 참고로 장고에서 모델을 정의할 때 Primary Key로 명시한 필드가 없다면 자동으로 Primary Key로서 id
필드가 정의된다. 데이터베이스에 모델 인스턴스가 저장될 때마다 id
필드의 값은 1씩 증가한다. 따라서 아래의 Snippet
모델은 실제로 7개의 필드를 가지고 있다고 생각해야 한다.▼
snippets/models.py
▼ 데이터베이스 마이그레이션
2. 시리얼라이저 정의하기 ① - Serializer 클래스
REST API를 제공하는 장고 애플리케이션은 API를 요청한 애플리케이션과 JSON 데이터를 주고받을 수 있어야 한다. 이를 위해서는 DB 인스턴스를 JSON 데이터로 시리얼라이즈 하거나, 반대로 JSON 데이터를 DB 인스턴스로 디시리얼라이즈 할 수 있어야 한다. 이러한 목적으로 DRF가 제공하는 클래스가 바로
Serializer
이며(장고의 Form
클래스와 유사), 이를 상속하여 특정 모델에 대응하는 시리얼라이저를 정의하게 된다. 이러한 시리얼라이저를 이용하면 DB 인스턴스를 JSON 데이터로 표현할 수 있고, JSON 데이터를 바탕으로 DB 인스턴스를 생성하거나 수정할 수 있다.시리얼라이저에는 시리얼라이즈/디시리얼라이즈 되어야 하는 모델의 필드들이 정의된다. 대응하는 모델의 모든 필드들을 정의할 수도 있고, 일부 필드만 정의할 수도 있다. 여기에서 정의되는 필드의 값들은 시리얼라이즈 시 JSON 데이터로 표현할 때 사용이 되며, 디시리얼라이즈 시 DB 인스턴스를 생성하거나 수정할 때 사용이 된다. 그리고 각 필드에 명시되는
required
, max_length
, default
등의 유효성 플래그(Validation Flag)들은 디시리얼라이즈 시 해당 필드의 유효성이 어떻게 검사 되어야 하는지를 나타낸다. 더불어서, 어떤 플래그들은 HTML에 렌더링 할 때와 같이 특정한 상황에서 해당 시리얼라이저가 어떻게 디스플레이되어야 하는지 지정할 수도 있다(EX. style
). 이는 Browsable API가 화면에 디스플레이되는 방식을 지정하고자 할 때 매우 유용하게 쓰인다.그리고 시리얼라이저에는
create()
메소드와 update()
메소드를 정의해줘야 한다. create()
메소드는 시리얼라이저를 대상으로 save()
메소드를 호출함으로써 DB 인스턴스를 생성하고자 할 때의 동작을 정의해야 하고, update()
메소드는 시리얼라이저를 대상으로 save()
메소드를 호출함으로써 DB 인스턴스를 수정하고자 할 때의 동작을 정의해야 한다.▼
snippets/serializers.py
3. 시리얼라이저 정의하기 ② - ModelSerializer 클래스
장고가
Form
클래스에 대응하는 ModelForm
클래스를 제공하는 것과 마찬가지로, DRF도 Serializer
클래스에 대응하는 ModelSerializer
클래스를 제공한다. ModelSerializer
는 특별한 것이 아니다. 그저 시리얼라이저를 더욱 편하게 정의할 수 있도록 리팩토링을 해줄 뿐이다. ModelSerializer
클래스가 제공하는 대표적인 기능은 다음과 같이 두 가지이다.- 시리얼라이즈/디시리얼라이즈 되어야 하는 모델 필드들을 자동으로 정의해준다. 따라서 정의할 모델의 필드명만 명시해주면 그것들의 타입에 맞게 시리얼라이저의 필드들이 자동으로 정의가 된다.
create()
메소드와update()
메소드를 가장 기본적인 형태로 이미 구현해 놓았다. 따라서 특별한 세부 구현이 필요하지 않은 경우에는 굳이 두 메소드를 정의해줄 필요가 없다. 세부 구현이 필요한 경우에는 오버라이딩을 하면 된다.
▼
snippets/serializers.py
▼ 시리얼라이저의 필드 정보 확인하기 (
python manage.py shell
)4. 시리얼라이저 다루기 ★★★
▼ 시리얼라이저 다루기 (
python manage.py shell
)4. REST API 뷰 정의하기 (일반적인 장고 뷰)
이제 앞서 정의한 시리얼라이저를 바탕으로, DB 인스턴스를 대상으로 요청할 수 있는 가장 기본적인 형태의 REST API 뷰들을 정의해보도록 하자. 여기서 기본적인 형태의 REST API 뷰라 함은 DB 인스턴스의 목록 조회(List), 생성(Create), 조회(Retrieve), 수정(Update), 삭제(Delete)를 위한 뷰를 의미한다.
여기서 정의하는 뷰들은 시리얼라이저를 사용할 뿐, 일반적인 장고의 뷰와 크게 다르지 않다. 심지어 당장 처리하지 않은 여러 예외 케이스들도 꽤 있다. 예를 들어, 잘못된 형태의 JSON 데이터로 HTTP 요청을 보냈을 때, 혹은 뷰가 처리할 수 없는 메소드로 HTTP 요청을 보냈을 때 등등이 그렇다. 이러한 경우에는 서버 500 에러가 발생할 것이다. 그럼에도 불구하고 이렇게 뷰들을 정의한 것은 REST API 뷰의 동작 원리를 밑바닥부터 설명해주기 위함이라고 받아들이면 될 것이다. 추후 포스팅에서는 REST API 뷰를 편리하게 정의할 수 있도록 DRF가 제공하는 몇몇 기능들을 살펴볼 것이다. 그 기능들을 사용하면 REST API 뷰를 정의하는 것이 훨씬 간편해질 뿐만 아니라, 여러 예외 상황에 대한 처리도 어느 정도 자동으로 해준다. 이에 대해서는 나중에 더 자세히 알아보자.
참고로
@csrf_exempt
는 CSRF 토큰이 없는 클라이언트에서도 POST 요청을 테스트해볼 수 있도록 하기 위한 데코레이터이다. 곧이어 아래에서 httpie
라는 HTTP 클라이언트를 이용해 우리가 정의한 뷰에 테스트 요청을 보내볼 것이기 때문이다.▼
snippets/views.py
▼
snippets/urls.py
▼
tutorial/urls.py
5. HTTP 클라이언트로 API 테스트해보기
우리가 정의한 REST API 뷰들이 제대로 동작하는지 한 번 테스트해보자. 이를 위해, 우선
python manage.py runserver
명령어로 장고 애플리케이션 서버를 실행하자. 그리고 또 다른 터미널을 켜서 그곳에서 HTTP 클라이언트를 통해 우리의 서버에 HTTP 요청을 보내보자. 그러려면 먼저 HTTP 클라이언트를 설치해야 한다. 여러 종류의 HTTP 클라이언트가 있지만, 그중에서 우리는 파이썬으로 만들어진 httpie
라는 HTTP 클라이언트를 사용해볼 것이다. pip install httpie
명령어로 httpie
파이썬 패키지를 설치하자.이제 다음과 같이 입력하여 HTTP 요청을 보내보자. 뷰가 제대로 동작한다면 우리가 요청한 DB 인스턴스(들)의 정보가 JSON 형태의 응답으로 날아올 것이다. 마찬가지로, 웹 브라우저에서 아래의 URL로 접속하더라도 동일한 JSON 데이터가 디스플레이될 것이다.
http http://127.0.0.1:8000/snippets/
http http://127.0.0.1:8000/snippets/0/
6. 마무리의 말
이번 포스팅에서는 모델과 그 모델에 대응하는 시리얼라이저를 정의하고, 이를 이용한 REST API 뷰들을 정의해 보았다. 그러나 이 뷰들은 시리얼라이저를 이용하여 JSON 데이터로 응답을 보내주도록 할 뿐, 일반적인 장고의 뷰와 크게 다르지 않다. 심지어 몇몇 예외 케이스에 대한 처리도 되어 있지 않다. 다음 포스팅에서는 이러한 것들을 조금 더 개선하기 위한 내용을 다뤄보도록 하자.