Django Rest Framework

Django Rest Framework 사용하기

  • Views.py에서 만든 뷰를 Templates에서 활용해야 할 경우, django Template filter를 사용해야 한다.
  • 프론트엔드 개발자도 django에 대해서 어느정도 알아야 한다는 말이 된다.
  • 이렇게 되면 프론트엔드와 백엔드는 끊임없이 함께 코드를 고쳐야 한다.
  • 따라서 프론트엔드와 백엔드가 완전히 구별되는 것이 이상적인데 이 때 필요한 것이 REST API이다.
  • Django에서는 Django Rest Framework(DRF)를 사용하여 코드를 작성한다.

API 실습을 위한 프로젝트 실습

  1. django project를 생성하고 앱을 생성한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ pip install django

    $ django-admin startproject config .

    # 회원 관리를 위한 앱
    $ python manage.py startapp accounts

    # 문서 작성을 위한 앱
    $ python manage.py startapp tweet
  2. Django Rest Framework를 설치한다.

    1
    $ pip install djangorestframework
  3. settings.py에서 INSTALLED_APPS에 ‘rest_framework’를 추가한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 생성한 앱도 추가하는 것을 잊지 말자.
    'accounts',
    'tweet',
    'rest_framework',
    ]
  4. 유저 모델을 커스텀하고 데이터베이스는 아마존 AWS를 사용한다.

    • 유저 모델을 커스텀한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      # accounts/models.py
      from django.db import models
      from django.contrib.auth.models import AbstractUser

      class User(AbstractUser):
      message = models.TextField(blank=True)
      profile = models.ImageField(upload_to='user_image/profile/%Y/%m/%d', blank=True)


      # config/settings.py
      AUTH_USER_MODEL = 'accounts.User'


      # accounts/admin.py
      from django.contrib import admin
      from django.contrib.auth import get_user_model

      # Register your models here.
      from django.contrib.auth.admin import UserAdmin

      class CustomUserAdmin(UserAdmin):
      UserAdmin.fieldsets[1][1]['fields'] += ('profile','message')

      UserAdmin.add_fieldsets += (
      (('Additional Info'), {'fields':('profile','message')}),
      )

      admin.site.register(get_user_model(), CustomUserAdmin)
    • 아미존 AWS에서 RDS에 데이터베이스를 생성하고 settings.py를 수정한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
       # psycopg2-binary를 설치하도록 한다.
      # 생성한 데이터베이스의 정보를 입력하도록 하자.
      DATABASES = {
      'default': {
      'ENGINE': 'django.db.backends.postgresql_psycopg2',
      'NAME': 'tweet',
      'USER':'마스터 사용자 이름',
      'PASSWORD':'마스터 사용자 비밀번호',
      'HOST':'아마존 RDS의 엔드포인트',
      'POST':'데이터베이스 접속 포트번호',
      },
      }
      # migrate하는 것을 잊지 말자.
  5. 뷰를 동작하려면 Serializer와 View가 필요하다.

    • Serializer는 API에서 동작하는 데이터 표현 객체이다.
    • ModelForm과 비슷하다고 생각하면 된다.
    • accounts 앱에서 serializers.py를 생성하고 다음과 같이 작성한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
       # accounts/serializers.py
      from rest_framework import serializers
      from .models import User

      # 유저 목록에 출력될 형식 지정
      class UserListSerializer(serializers.ModelSerializer):
      class Meta:
      model = User
      fields = ['id', 'username', 'first_name', 'last_name', 'email', 'message', 'profile']
      # fields = '__all__'로 전부 불러올 수도 있다.
    • views.py에 API 뷰를 작성하도록 한다.

    • 함수형 뷰와 클래스형 뷰 모두 만들 수 있다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      from django.shortcuts import render
      from .serializers import UserListSerializer
      from django.contrib.auth import get_user_model
      from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
      from rest_framework import generics
      """
      # generics 안에는 CRUD가 있다.
      List : GET
      Create : POST
      Retrieve : GET
      Update : PUT, PATCH
      Destroy : Delete
      """
      class UserListView(generics.ListAPIView):
      # renderer_classes = [JSONRenderer] # JSON 형식으로만 받고 싶은 경우
      queryset = get_user_model().objects.all()
      serializer_class = UserListSerializer

      def get_queryset(self):
      queryset = super().get_queryset()
      if not self.request.user.is_staff:
      queryset = queryset.filter(pk=self.request.user.id)
      return queryset
    • urls.py를 생성하고 작성한다.

      1
      2
      3
      4
      5
      6
      from django.urls import path
      from .view import *

      urlpatterns = [
      path('list/', UserListView.as_view()),
      ]
    • config/urls.py에도 accounts 앱을 연결해준다.

      1
      2
      3
      4
      5
      6
      7
      from django.contrib import admin
      from django.urls import path, include

      urlpatterns = [
      path('admin/', admin.site.urls),
      path('accounts/', include('accounts.urls')),
      ]
    • 서버 접속을 통해 유저 리스트가 나오는지 확인한다.

    • 상세(Detail), 생성(Create), 수정(Update), 삭제(Delete) 모두 생성해보자.
    • serializers.py에 추가 작성한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      from rest_framework import serializers
      from .models import User

      # 유저 목록에 출력될 형식 지정
      # List
      class UserListSerializer(serializers.ModelSerializer):
      class Meta:
      model = User
      fields = ['id', 'username', 'first_name', 'last_name', 'email', 'message', 'profile']

      # 회원 가입할 때 필요한 필드들에 관한 Serializer
      # Create
      class UserCreateSerializer(serializers.ModelSerializer):
      class Meta:
      model = User
      fields = ['username', 'password', 'first_name', 'last_name', 'email', 'message', 'profile']

      # create method를 사용하지 않으면 password가 그대로 들어가게 된다.
      # 관리자 페이지에 가보면 password가 제대로 저장되지 않는 것을 확인할 수 있다.
      def create(self, validated_data):
      user = User.objects.create(**validated_data)
      user.set_password(validated_data.get('password'))
      user.save()
      return user # create는 방금 만든 오브젝트를 반드시 리턴해줘야 한다.

      # Update
      class UserModifySerializer(serializers.ModelSerializer):
      class Meta:
      model = User
      fields = ['password', 'first_name', 'last_name', 'email', 'message', 'profile']

      # 기존의 update 함수를 오버라이딩해서 사용한다.
      # password만 수정하고 다른 정보는 빈 칸으로 둘 경우, 다른 정보들이 빈 칸으로 저장된다.
      # 따라서 기존의 update method를 오버라이딩해서 사용하도록 한다.
      def update(self, instance, validated_data):
      for key, value in validated_data.items():
      if key == 'password' and value:
      instance.set_password(value)
      elif value:
      setattr(instance, key, value)
      instance.save()
      return instance

      # Detail
      class UserDetailSerializer(serializers.ModelSerializer):
      class Meta:
      model = User
      fields = ['id', 'username', 'password', 'first_name', 'last_name', 'email', 'message', 'profile', 'is_superuser']
    • views.py를 작성한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      from django.shortcuts import render
      from .serializers import UserListSerializer, UserCreateSerializer ,UserModifySerializer, UserDetailSerializer
      from django.contrib.auth import get_user_model
      from rest_framework import generics
      from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
      """
      # generics 안에는 CRUD가 있다.
      List : GET
      Create : POST
      Retrieve : GET
      Update : PUT, PATCH
      Destroy : Delete
      """

      # List View
      class UserListView(generics.ListAPIView):
      # renderer_classes = [JSONRenderer] # JSON 형식으로만 받고 싶은 경우
      queryset = get_user_model().objects.all()
      serializer_class = UserListSerializer

      # 관리자는 모든 유저 목록을 볼 수 있다.
      # 관리자가 아닌 유저는 자신의 정보만 볼 수 있다.
      def get_queryset(self):
      queryset = super().get_queryset()
      if not self.request.user.is_staff:
      queryset = queryset.filter(pk=self.request.user.id)
      return queryset

      # Create View
      class UserCreateView(generics.CreateAPIView):
      serializer_class = UserCreateSerializer

      # Update View
      class UserUpdateView(generics.UpdateAPIView):
      queryset = get_user_model().objects.all()
      serializer_class = UserModifySerializer

      # Detail View
      class UserDetailView(generics.RetrieveAPIView):
      queryset = get_user_model().objects.all()
      serializer_class = UserDetailSerializer

      # Delete View
      # 삭제할 시, 형식을 지정할 필요가 없으므로, Serializer_class는 필요없다.
      class UserDeleteView(generics.DestroyAPIView):
      queryset = get_user_model().objects.all()
    • urls.py를 작성한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      from django.urls import path
      from .views import *

      urlpatterns = [
      path('delete/<int:pk>/', UserDeleteView.as_view()),
      path('detail/<int:pk>/', UserDetailView.as_view()),
      path('update/<int:pk>/', UserUpdateView.as_view()),
      path('create/', UserCreateView.as_view()),
      path('list/', UserListView.as_view()),
      ]
    • 서버 접속을 통해 동작을 확인해보자.

  6. 이번엔 tweet 앱을 작성해보자.

    • models.py를 간단하게 작성한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      from django.db import models
      from django.contrib.auth import get_user_model

      class Tweet(models.Model):
      author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='tweets')
      text = models.TextField()
      created = models.DateTimeField(auto_now_add=True)
      updated = models.DateTimeField(auto_now=True)

      # migrate하는 것을 잊지 말자.
    • 같은 방법으로 serializers.py를 생성하여 작성한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      from rest_framework import serializers
      from .models import Tweet

      class TweetListSerializer(serializers.ModelSerializer):
      class Meta:
      model = Tweet
      fields = '__all__'

      class TweetSerializer(serializers.ModelSerializer):
      class Meta:
      model = Tweet
      fields = ['author', 'text']
    • views.py를 작성한다.

    • 위와 같이 각각 뷰마다 작성하는 방법이 있다.
    • 다른 방법으로는 generics에 공통 뷰를 사용하는 방법도 있다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      from django.shortcuts import render
      from .serializers import TweetListSerializer, TweetSerializer
      from . models import Tweet
      from rest_framework import generics

      # List & Create View
      class TweetListCreateView(generics.ListCreateAPIView):
      queryset = Tweet.objects.all()
      serializer_class = TweetListSerializer

      def create(self, request, *args, **kwargs):
      # print(request.user.id)
      # api를 공부하면서 print()를 이용해서 값을 받아보는 습관을 들이자.
      request.data['author'] = request.user.id
      # 기존 form에서는 form.instance.author를 사용
      # 다른 점을 살펴보자.
      return super().create(request, *args, **kwargs)

      # Retrieve & Update & Destroy View
      class TweetDetailView(generics.RetrieveUpdateDestroyAPIView):
      queryset = Tweet.objects.all()
      serializer_class = TweetSerializer

      # class TweetListView(generics.ListAPIView):
      # queryset = Tweet.objects.all()
      # serializer_class = TweetListSerializer
      #
      # class TweetCreateView(generics.CreateAPIView):
      # serializer_class = TweetSerializer
      #
      # class TweetDetailView(generics.RetrieveAPIView):
      # queryset = Tweet.objects.all()
      # serializer_class = TweetSerializer
      #
      # class TweetUpdateView(generics.UpdateAPIView):
      # queryset = Tweet.objects.all()
      # serializer_class = TweetSerializer
      #
      # class TweetDeleteView(generics.DestroyAPIView):
      # queryset = Tweet.objects.all()
    • urls.py를 생성하고 작성한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      from django.urls import path
      from .views import *

      urlpatterns = [
      path('', TweetListCreateView.as_view()),
      path('<int:pk>/', TweetDetailView.as_view()),
      # path('', TweetListView.as_view()),
      # path('create/', TweetCreateView.as_view()),
      # path('detail/<int:pk>', TweetDetailView.as_view()),
      # path('update/<int:pk>', TweetUpdateView.as_view()),
      # path('delete/<int:pk>', TweetDeleteView.as_view()),

      ]
    • config/urls.py에도 tweet 앱을 연결한다.

      1
      2
      3
      4
      5
      6
      7
      8
      from django.contrib import admin
      from django.urls import path, include

      urlpatterns = [
      path('admin/', admin.site.urls),
      path('accounts/', include('accounts.urls')),
      path('tweet/', include('tweet.urls')),
      ]
    • 서버에 접속하여 동작을 확인하도록 한다.

  7. API 문서를 만들어서 한 눈에 모든 뷰를 확인해보도록 하자.

    • swagger를 설치한다.

      1
      2
      # 입력한 토큰이 사라지는 버그로 인해 2.1.2 버전을 설치한다.
      $ pip install django-rest-swagger==2.1.2
    • settings.py에서 INSTALLED_APPS에 ‘rest_framework_swagger’를 추가한다.

      1
      2
      3
      4
      INSTALLED_APPS = [
      #...
      'rest_framework_swagger',
      ]
    • config/urls.py에 swagger에 관한 뷰를 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      from django.contrib import admin
      from django.urls import path, include
      # get_swagger_view 추가
      from rest_framework_swagger.views import get_swagger_view
      from rest_framework.authtoken.views import obtain_auth_token

      # API 문서의 제목 지정
      schema_view = get_swagger_view(title='Tweeter API Document')

      urlpatterns = [
      path('api/get_token/', obtain_auth_token),
      # 경로 추가
      path('api/doc/', schema_view),
      path('admin/', admin.site.urls),
      path('accounts/', include('accounts.urls')),
      path('tweet/', include('tweet.urls')),
      ]
    • 이제 해당 경로로 접속하여 API 문서 뷰를 확인해보자.

  8. 이제 API에서 가장 많이 사용하는 토큰 인증 방식을 추가해보도록 한다.

    • settings.py에서 INSTALLED_APPS에 ‘rest_framework.authtoken’을 추가한다.

      1
      2
      3
      4
      INSTALLED_APPS = [
      #...
      'rest_framework.authtoken',
      ]
    • 토큰 기능을 추가하면 추가 테이블이 필요하므로 migrate를 하도록 한다.

    • config/urls.py에 토큰 관련 뷰를 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      from django.contrib import admin
      from django.urls import path, include
      from rest_framework_swagger.views import get_swagger_view
      # obtain_auth_token 추가
      from rest_framework.authtoken.views import obtain_auth_token

      schema_view = get_swagger_view(title='Tweeter API Document') # API 문서의 제목

      urlpatterns = [
      # 경로 추가
      path('api/get_token/', obtain_auth_token),
      path('api/doc/', schema_view),
      path('admin/', admin.site.urls),
      path('accounts/', include('accounts.urls')),
      path('tweet/', include('tweet.urls')),
      ]
    • API 문서 페이지에 접속하여 토큰을 발급받아본다.

      • api의 POST /api/get_token을 누르고 오른쪽에 Example Value를 클릭한다.
      • 왼쪽 Value에 Example Value 형식이 들어가면 입력하도록 한다.
      • 발급받은 토큰을 알아두자.
  9. 모든 API 뷰가 로그인해야만 동작할 수 있도록 권한을 추가하도록 한다.

    • settings.py에 관련 설정을 추가한다.

      1
      2
      3
      4
      5
      REST_FRAMEWORK = {
      'DEFAULT_PERMISSION_CLASSES': (
      'rest_framework.permissions.IsAuthenticated',
      ),
      }
    • 로그아웃했을 때 토큰 발급만 되는 것을 확인할 수 있다.

    • 하지만 회원 가입같은 경우, 인증하지 않아도 사용하는 뷰이므로, 다음과 같은 코드를 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      # accounts/views.py
      # AllowAny 추가
      from rest_framework.permissions import AllowAny

      class UserCreateView(generics.CreateAPIView):
      serializer_class = UserCreateSerializer
      # permission_classes 추가
      permission_classes = (AllowAny,)
    • swagger 페이지에서도 토큰을 인증할 수 있도록 settings.py에 다음과 같은 코드를 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      REST_FRAMEWORK = {
      'DEFAULT_PERMISSION_CLASSES': (
      'rest_framework.permissions.IsAuthenticated',
      ),
      # 추가
      'DEFAULT_AUTHENTICATION_CLASSES': (
      'rest_framework.authentication.TokenAuthentication',
      ),
      }

      # 추가
      SWAGGER_SETTINGS = {
      'SECURITY_DEFINITIONS': {
      "api_key": {
      "type": "apiKey",
      "name": "Authorization",
      "in": "header"
      }
      }
      }
    • 이제 swagger 페이지에서 오른쪽 상단에 Authorize를 누르면 토큰 키를 입력할 수 있다.

      1
      2
      # value에 다음과 같이 입력하면 된다.
      value: Token [토큰 값]
    • 이번에는 자신이 작성한 글이거나 관리자인 경우에만 글에 대한 권한을 가질 수 있도록 해본다.

    • tweet/permissions.py를 생성하고 작성한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      from rest_framework import permissions

      # 작성자인 경우
      # 반환값은 boolean
      class IsOwnerOnly(permissions.BasePermission):
      def has_object_permission(self, request, view, obj):
      return obj.author == request.user

      # 작성자이거나 관리자인 경우
      class IsOwnerAndAdminOnly(permissions.BasePermission):
      def has_object_permission(self, request, view, obj):
      return obj.author == request.user or request.user.is_superuser

      class IsOwnerOrReadOnly(permissions.BasePermission):
      def has_object_permission(self, request, view, obj):
      if request.method in permissions.SAFE_METHODS:
      # SAPE_METHODS : GET, HEAD, OPTIONS - 값을 변경하지 않는 메소드
      return True

      return obj.author == request.user or request.user.is_superuser
    • tweet/views.py에 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      # permissions 추가
      from .permissions import *
      # IsAuthenticated 추가
      from rest_framework.permissions import IsAuthenticated

      class TweetDetailView(generics.RetrieveUpdateDestroyAPIView):
      queryset = Tweet.objects.all()
      serializer_class = TweetSerializer
      # 로그인을 하지 않으면 사용 못함
      permission_classes = [IsAuthenticated, IsOwnerAndAdminOnly]
  10. 필터 기능을 활용해보자.

    • django-filter를 설치한다.

      1
      $ pip install django-filter
    • settings.py에서 INSTALLED_APPS에 ‘diango_filters’ 및 관련 설정을 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      INSTALLED_APPS = [
      #...
      'django_filters',
      ]

      REST_FRAMEWORK = {
      'DEFAULT_PERMISSION_CLASSES': (
      'rest_framework.permissions.IsAuthenticated',
      ),
      'DEFAULT_AUTHENTICATION_CLASSES': (
      'rest_framework.authentication.TokenAuthentication',
      ),
      # 추가
      'DEFAULT_FILTER_BACKENDS': (
      'django_filters.rest_framework.DjangoFilterBackend',
      )
      }
    • 필터 기능을 동작하고 싶은 뷰에 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      class UserListView(generics.ListAPIView):
      # renderer_classes = [JSONRenderer] # JSON 형식으로만 받고 싶은 경우
      queryset = get_user_model().objects.all()
      serializer_class = UserListSerializer
      # 필터 기능 추가
      filterset_fields = ('username', 'first_name')

      def get_queryset(self):
      queryset = super().get_queryset()
      if not self.request.user.is_staff:
      queryset = queryset.filter(pk=self.request.user.id)
      return queryset
    • swagger 페이지로 접속하여 해당 파라미터에 필드가 적용되었는지 확인한다.

    • 이번에는 검색 필드를 사용해보도록 한다.
      • ForeignKey로 묶인 필드들을 기준으로 검색할 수 있다.
    • settings.py에 관련 설정을 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      REST_FRAMEWORK = {
      'DEFAULT_PERMISSION_CLASSES': (
      'rest_framework.permissions.IsAuthenticated',
      ),
      'DEFAULT_AUTHENTICATION_CLASSES': (
      'rest_framework.authentication.TokenAuthentication',
      ),
      'DEFAULT_FILTER_BACKENDS': (
      'django_filters.rest_framework.DjangoFilterBackend',
      # 추가
      'rest_framework.filters.SearchFilter'
      )
      }
    • 검색하고자 하는 필드를 뷰에 추가한다.

    • ForeignKey로 묶인 필드의 경우, 언더바 두 개(__)를 사용하여 필드명을 작성하면 된다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      class TweetListCreateView(generics.ListCreateAPIView):
      queryset = Tweet.objects.all()
      serializer_class = TweetListSerializer
      # 검색 기능 추가
      search_fields = ('text', 'author__username')

      def create(self, request, *args, **kwargs):
      request.data['author'] = request.user.id
      return super().create(request, *args, **kwargs)
    • swagger 페이지로 접속하여 파라미터에 search 기능이 나오는지 확인한다.

  11. Postman에서도 확인할 수 있다.

    • Postman을 설치하고 실행한다.
    • 유저 리스트를 보기 위해 다음과 같이 설정한다.

      1
      2
      3
      4
      5
      6
      Method : GET
      Address : 127.0.0.1:8000/accounts/list
      Headers : KEY - Authorization
      VALUE - Token [토큰 값]

      위 설정을 입력하고 SEND를 누른다.
    • 유저 리스트가 나오는지 확인하자.

    • tweet 앱에서 글을 작성할 경우 다음과 같이 설정한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      Method : POST
      Address : 127.0.0.1:8000/tweet/
      Headers : KEY - Authorization
      VALUE - Token [토큰 값]
      Body : raw/JSON(application/json) 선택
      Body 내용: {
      "text": "test",
      "author": 1
      }
    • 결과를 확인한다.

    • 설정하는 내용은 swagger 페이지에서 확인하면 된다.
      • 메소드와 형식, 입력하는 곳이 어디인지 확인해서 적용하자.
Share