JSON 응답뷰 만들기

JSON 응답뷰 만들기

2018, Sep 16    

API 서버는 무엇일까요?

  • 앱/웹 서비스를 만드는 개발자들이 이용하는 데이터 위주의 서비스
  • API 서버는 시간이 지나도 호환성을 유지해야 합니다.
    • 따라서 API 버전의 개념을 두어야 합니다.
      • ex) /api/v1/posts, /api/v2/posts/
  • djangorestframework(이하 DRF)는 REST API를 만드는 데 도움을 줍니다.
    • URI는 `https://{serviceRoot}/{collection}/{id}’ 형식이어야 합니다.
    • DRF는 GET, PUT, DELETE, POST, HEAD, PATCH, OPTIONS 기능을 지원해야 합니다.
    • API 버전은 Major.minor 형태로 관리하고 URI에 버전 정보를 포함시켜야 합니다.
  • DRF는 장고의 Form/CBV을 컨셉을 그대로 가져왔습니다. 따라서 장고 Form/CBV를 잘 이해한다면 DRF에 대해서도 보다 깊은 이해가 가능합니다.


CRUD

  • 모든 데이터는 기본적으로 Create/Read/Update/Delete 로 관리가 되어야 합니다.
    • C : Create (레코드 생성)
    • R : Read (레코드 목록 조회, 특정 레코드 상세 조회)
    • U : Update (특정 레코드 수정)
    • D : Delete (특정 레코드 삭제)


REST API URL 예제

  • REST API 식의 URL로 설계를 해보면 다음과 같이 해볼 수 있습니다.
    • /post/주소
      • GET 방식 요청 : 목록 응답
      • POST 방식 요청 : 새 글 생성하고, 확인 응답
    • /post/1/주소
      • GET 방식 요청 : 1번글 응답
      • PUT 방식 요청 : 1번글 갱신하고 확인 응답
      • DELETE 방식 요청 : 1번글 삭제하고 확인 응답
  • djangorestframework는 REST API 구현을 도와주는 Class Based View를 제공해주는 프레임워크입니다.


django rest framework setting

flow


  • 먼저 프로젝트를 하나 만들어 보겠습니다. 커맨드 라인에 다음과 같이 입력하면 프로젝트가 생성됩니다.
django-admin startproject djangoRestApi
cd/djangoRestApi


  • 프로젝트에서 사용할 앱을 만들어 보겠습니다. 앱 이름은 sample로 지정해보면 아래와 같습니다.
    python manage.py startapp sample
    


djangoRestApi/settings.py, 에서 INSTALLED_APPSrest_framework, sample.를 추가해 보겠습니다.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
	'rest_framework',
	'sample',
]


  • 앱에서 모델을 추가해 보겠습니다.
# sample/models.py
from django.db import models

class Post(models.Model):
    message = models.TextField()


  • 같은 디렉토리에서 다음과 같이 serializers.py를 만들고 안에 코드를 추가해 보겠습니다.
# myapp/serializers.py
from rest_framework import serializers
from .models import Post

# ModelSerializer (instead of ModelForm)
class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = '__all__'


  • views.py에 Serializers.py에서 작성한 내용을 불러오겠습니다.
# myapp/views.py
from django.shortcuts import render
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer


  • sample/urls.py에서 views.py에 선언된 값들을 url로 연결해줍니다.
# sample/urls.py
from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()
router.register(r'posts', views.PostViewSet)

urlpatterns = [
    url(r'', include(router.urls)),
]


API 호출

+API 뷰 호출은 다양한 클라이언트 프로그램에 의하여 호출될 수 있습니다. + JavaScript from web frontend + Android/iOS app code + Library (ex.requests) + CLI Program : cURL, HTTPie

HTTPie 란?

  • 다음 명령어를 통해 간단히 설치할 수 있습니다.
pip install --upgrade httpie


  • 설치를 하면 CLI에서 http라는 명령어를 사용할 수 있습니다.
  • 예를 들면 다음과 같습니다.
shell> http GET `request address` `GET parameter`==value `GET parameter`== <br>
shell> http --json POST `request address` `GET parameter`==value `GET parameter`== `POST parameter`==value `POST parameter`==value <br>
shell> http --form POST `request address` `GET parameter`==value `GET parameter`== `POST parameter`==value `POST parameter`==value <br>
shell> http PUT `request address` `GET parameter`==value `GET parameter`== `POST parameter`==value `POST parameter`==value <br>
shell> http DELETE `request address` `GET parameter`==value `GET parameter`== 


  • 참고로 GET 인자에는 ==을 사용하고 POSㅆ 인자에는 =를 사용하였습니다.

  • POST requests는 다음과 같이 두 가지 방식으로 나뉘어 집니다.

    • In specifying --form : multipart/form-data 요청 : HTML Form과 동일합니다.
    • In specifying --json or 생략 시 : application/json 요청 : 요청 데이터를 JSON포맷으로 직렬화해서 전달합니다.


  • GET request 예시
shell> http GET httpbin.org/get x==1 y==2

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 296
Content-Type: application/json
Date: Sat, 14 Oct 2017 18:37:49 GMT
Server: meinheld/0.6.1
Via: 1.1 vegur
X-Powered-By: Flask
X-Processed-Time: 0.000959157943726

{
    "args": {
        "x": "1",
        "y": "2"
    },
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "close",
        "Host": "httpbin.org",
        "User-Agent": "HTTPie/0.9.9"
    },
    "origin": "221.148.61.230",
    "url": "http://httpbin.org/get?x=1&y=2"
}


  • POST request 예시
shell> http --form POST "httpbin.org/post" a=1 b=2 c=3

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 469
Content-Type: application/json
Date: Sat, 14 Oct 2017 18:43:14 GMT
Server: meinheld/0.6.1
Via: 1.1 vegur
X-Powered-By: Flask
X-Processed-Time: 0.00148487091064

{
    "args": {},
    "data": "",
    "files": {},
    "form": {
        "a": "1",
        "b": "2",
        "c": "3"
    },
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "close",
        "Content-Length": "11",
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
        "Host": "httpbin.org",
        "User-Agent": "HTTPie/0.9.9"
    },
    "json": null,
    "origin": "221.148.61.230",
    "url": "http://httpbin.org/post"
}


  • PUT request 예시
shell> http PUT httpbin.org/put hello=world

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 452
Content-Type: application/json
Date: Sat, 14 Oct 2017 18:37:05 GMT
Server: meinheld/0.6.1
Via: 1.1 vegur
X-Powered-By: Flask
X-Processed-Time: 0.00133204460144

{
    "args": {},
    "data": "{\"hello\": \"world\"}",
    "files": {},
    "form": {},
    "headers": {
        "Accept": "application/json, */*",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "close",
        "Content-Length": "18",
        "Content-Type": "application/json",
        "Host": "httpbin.org",
        "User-Agent": "HTTPie/0.9.9"
    },
    "json": {
        "hello": "world"
    },
    "origin": "221.148.61.230",
    "url": "http://httpbin.org/put"
}


  • DELETE request 예시
shell> http DELETE "httpbin.org/delete"

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 351
Content-Type: application/json
Date: Sat, 14 Oct 2017 18:42:44 GMT
Server: meinheld/0.6.1
Via: 1.1 vegur
X-Powered-By: Flask
X-Processed-Time: 0.000683069229126

{
    "args": {},
    "data": "",
    "files": {},
    "form": {},
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "close",
        "Content-Length": "0",
        "Host": "httpbin.org",
        "User-Agent": "HTTPie/0.9.9"
    },
    "json": null,
    "origin": "221.148.61.230",
    "url": "http://httpbin.org/delete"
}