RESTful API
Representation State Transfer => 상태를 표현하는 전송
- 로그인 할 때 => prfile/me => 응답을 받아옴
- Application Porgramming Interface
- 행동을 HTTP Method(get/ post/ put/ patch/ delete)를 사용하여 표현한다.
/
슬래시는 계층 관계를 나타낼때 사용- 마지막 슬래시는 포함하지 않는다.
- Resource들은 명사를 사용한다.
_
보다-
을 권장한다.- 소문자를 사용
- 파일 확장자를 포함하지 않음
- 응답은 JSON이 대세
Single Page Application
# blog/views/api_views.py
from django.http import JsonResponse
from blog.models import Blog
@csrf_exempt
def blog_list(request):
if request.method == 'GET':
blogs = Blog.objects.all()
data = {
'blog_list': [{'id': blog.id, 'title': blog.title} for blog in blogs]
}
return JsonResponse(data, status=200)
else:
body = json.loads(request.body.decode('utf-8'))
blog = Blog.objects.create(
**body, # 딕셔너리를 위에 작성해놓으면 맞추숴 넣어짐
author=User.objects.first()
)
data = {
'id' : blog.id,
'title' : blog.title,
'content' : blog.content,
'author' : blog.author.username
}
return JsonResponse(data, status=201) # 생성이기에 201 create
# blog/urls.py
app_name ='api'
urlpatterns = [
path('', api_views.blog_list, name='blog_list'),
]
# config/urls.py
path('api', include('blog.urls')),
APPEND_SLASH = False
넣어주면 / 있고 없고 차이를 구분함http://localhost:8000/api
요청 보내면 빈리스트 잘나올것임 젤끝에 / 슬래쉬 붙이면 오류Django REST Framework(DRF)는 Django에서 웹 API를 쉽게 구축할 수 있도록 도와주는 강력한 라이브러리입니다. DRF는 직렬화(Serialization), 뷰(View), 권한 부여(Authorization) 등의 기능을 제공하여 RESTful API 개발을 단순화합니다.
'rest_framework'
등록 -> permission 적용 아래와 같이 작성# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
# blog/serializers.py
from django.contrib.auth import get_user_model
from rest_framework import serializers
User = get_user_model()
# Form과 비슷한 역할
# 리턴하는 항목들도 필드에 적은 항목들만 리턴하도록 설계되어 있음, 스키마의 역할도 하는
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
# blog/views/api_views.py
from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet):
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
# viewsets: REST FRAMEWORK 의 특별한 기능
# ReadOnlyModelViewSet : List와 Detail의 API를 만들어줌
# ModelViewSet: : List, Detail, Put, Create, Delete, Fetch 가능
# blog/urls.py
from django.urls import path, include
from rest_framework import routers
from blog.views import api_views
app_name ='api'
router = routers.DefaultRouter(trailing_slash=False) # trailing_slash = False 슬래쉬가 있는지 없는지
router.register(r'users', api_views.UserViewSet, basename='user')
# prefix 에서 users 를 붙인것은 include에서 users 로 시작하라는 거와 같음 앞에 무조건 /api/users 라 한것임
# viewset이기에 사실 여러개의 페이지를 연결한 것임, 현재 list, detail 페이지
urlpatterns = [
# path('', api_views.blog_list, name='blog_list'),
path('',include(router.urls)),
]
# config/urls.py
urlpatterns = [
# path('', api_views.blog_list, name='blog_list'),
path('',include(router.urls)),
]
ReadOnlyViewSet
, ModelViewSet
어떻게 설게되어 있나 확인 가능Serializer는 Django 모델 인스턴스를 JSON과 같은 데이터 포맷으로 변환하거나, JSON 데이터를 모델 인스턴스로 변환하는 데 사용됩니다. 즉, 데이터의 직렬화와 역직렬화를 담당합니다.
from rest_framework import serializers
from .models import MyModel
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
APIView는 Django의 기본 View를 확장하여 RESTful API 엔드포인트를 생성할 수 있도록 해줍니다. APIView는 HTTP 메서드(GET, POST, PUT, DELETE 등)를 오버라이드하여 사용할 수 있습니다.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class MyAPIView(APIView):
def get(self, request):
data = {"message": "Hello, World!"}
return Response(data, status=status.HTTP_200_OK)
def post(self, request):
data = request.data
return Response(data, status=status.HTTP_201_CREATED)
Generic Views는 CRUD 작업을 간단히 처리할 수 있도록 미리 정의된 클래스입니다. Generic Views를 사용하면 반복적인 코드 작성을 줄일 수 있습니다.
from rest_framework import generics
from .models import MyModel
from .serializers import MyModelSerializer
class MyModelListCreateView(generics.ListCreateAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
ViewSet은 관련된 여러 뷰 로직을 하나의 클래스에 결합한 것입니다. ModelViewSet, ReadOnlyModelViewSet과 같은 기본 ViewSet을 사용하면, 더욱 간결하게 API를 정의할 수 있습니다.
from rest_framework import viewsets
from .models import MyModel
from .serializers import MyModelSerializer
class MyModelViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
Router는 URL과 ViewSet을 자동으로 연결해주는 기능을 합니다. 이를 통해 개발자는 URLConf를 일일이 작성할 필요 없이, ViewSet만으로 URL 매핑이 가능합니다.
from rest_framework.routers import DefaultRouter
from .views import MyModelViewSet
router = DefaultRouter()
router.register(r'mymodels', MyModelViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Permissions는 API에 대한 접근 권한을 제어하는 기능입니다. 기본적으로 DRF는 다양한 권한 클래스를 제공하며, 이를 통해 API 접근을 제한할 수 있습니다.
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
class MyAPIView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({"message": "Authenticated!"})
DRF는 다양한 인증 방식을 지원합니다. 기본적인 Session 인증, Token 인증 외에도 OAuth, JWT 등의 다양한 인증 방식을 사용할 수 있습니다.
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
class MyAPIView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({"message": "Token authenticated!"})
Throttling은 API 요청을 제한하는 기능입니다. 특정 시간 내에 요청할 수 있는 횟수를 제한하여 API 남용을 방지할 수 있습니다.
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class MyAPIView(APIView):
throttle_classes = [UserRateThrottle]
def get(self, request):
return Response({"message": "Throttled request!"})
# blog/serializers.py
class BlogSerializer(serializers.ModelSerializer):
author = UserSerializer(many=False) # ForeignKey 연결된것 연결하는것 serialzer 로 해놓은것만 이렇게 사용가능
# ✅ `many=False`: 1명의 사용자(User)만 연결되므로 `False` 설정 (ForeignKey 관계)
# ✅ `UserSerializer`를 사용하여 author 필드에 대한 직렬화(Serialization) 수행
# ✅ 이렇게 하면 API 응답에서 author의 ID만 반환되는 것이 아니라, UserSerializer에 정의된 필드까지 포함됨
# 이렇게 쓰면 꼭 까먹지말고 views 에서 select_related 등록하기
class Meta:
model = Blog
fields = ['title', 'content', 'author', 'published_at', 'created_at', 'updated_at']
# blog/views/api_views.py
class BlogViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Blog.objects.all().order_by('-date_joined').select_related('author')
serializer_class = BlogSerializer
# blog/urls.py
router.register(r'blogs', api_views.BlogViewSet, basename='blog')