티스토리 뷰
2019/07/22 - [Django] - REST API 이용하기
HTTP Method
요청 목적 |
HTTP Method |
SQL |
새로운 리소스 생성 |
POSTa |
INSERT |
리소스 읽기 |
GET |
SELECT |
리소스의 메타데이터 요청 |
HEAD |
|
리소스 데이터 업데이트 |
PUT |
UPDATE |
리소스의 부분 변경 |
PATCH |
UPDATE |
리소스 삭제 |
DELETE |
DELETE |
특정 URL에 대해 지원되는 HTTP 메서드 출력 |
OPTIONS |
|
요청(requests)에 대한 반환 에코 |
TRACE |
|
TCP/IP 터널링(일반적으로 구현되어 있지는 않음) |
CONNECT |
-
read-only API만 구현하다면 GET method만 구현
-
read-write API를 구현한다면 최소한 POST 메서드는 구현해야 하며 PUT과 DELETE 또한 고려
-
단순화하기 위해 때때로 REST API는 GET과 POST만으로 구현되도록 설계
-
GET, PUT, DELETE는 여러 번 실행해도 그 결과과 변하지 않는 멱등(idempotent)관계이며 POST와 PATCH는 그렇지 않다.
-
PATCH가 구현되어 있지 않은 경우도 있다. 하지만 API가 PUT 요청을 지원 한다면 PATCH 또한 구현하는 것이 좋다
-
django-rest-frameworks와 django-tastypie는 앞의 모든 경우를 처리한다.
HTTP 상태 코드
HTTP 상태 코드 |
성공/실패 |
의미 |
200 OK |
Success |
GET - 리소스 반환 PUT - 상태 메시지 제공 또는 리소스 반환 |
201 Created |
Success |
POST - 상태 메지시 반환 또는 새로 생성된 리소스 반환 |
204 No Content |
Success |
DELETE - 성공적으로 삭제된 요청의 응답 |
304 Unchanged |
Redirect |
ALL - 이전 요청으로부터 아무런 변화가 없음을 나타낸다. 성능 개선을 위해 마지막으로 수정된 리소스나 Etag 헤더를 확인하기 위해 이용한다. |
400 Bad Request |
Failure |
ALL - 폼 검증 에러를 포함한 에러 메시지 반환 |
401 Unauthorized |
Failure |
ALL - 인증 요청을 했으나 사용자가 인증 요건을 제공하지 않음 |
403 Forbidden |
Failure |
ALL - 사용자가 허용되지 않은 콘텐트로 접근을 시도함 |
404 Not Found |
Failure |
ALL - 리소스 없음 |
405 Method Not Allowed |
Failure |
ALL - 허가되지 않은 HTTP 메서드로 시도됨 |
410 Gone |
Failure |
ALL - 더는 제공되지 않는 메서드로 호출. 새 버전의 API를 제공하기 위해 기존 API 서비스를 중지할 때 이용된다. 모바일 애플리케이션의 경우 해당 결과에 대대 사용자에게 애플리케이션 업그레이드를 요청하는 방법을 쓰기도 한다. |
429 Too Many Requests |
Failure |
ALL - 제한 시간 내에 너무 많은 요청을 보냄. 접속 제한(rate limit)을 이용할 때 쓰인다. |
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
REST API 아키텍처
-
프로젝트 코드들은 간결하게 정리되어 있어야 한다.
-
앱의 코드는 앱 안에 두자
-
비즈니스 로직을 API 뷰에서 분리하기
- API URL을 모아 두기
- API 테스트하기
- API 버저닝하기
외부 API 중단하기
- 사용자들에게 서비스 중지 예고하기
- 410 에러 뷰로 API 교체하기
API에 접속 제한하기
- 제한 없는 API 접속은 위험하다
- REST 프레임워크는 반드시 접속 제한을 해야만 한다
- 비즈니스 계획으로서의 접속 제한
http://www.django-rest-framework.org/
https://django-tastypie.readthedocs.io/en/latest/
https://django-braces.readthedocs.io/en/latest/index.html
https://github.com/jsocol/django-jsonview
테스트 하기
import json
from django.urls import reverse
from django.test import TestCase
from flavors.models import Flavor
class FlavorAPITests(TestCase):
def setUp(self):
Flavor.objects.get_or_create(title="A Title", slug='a-slug')
def test_list(self):
url = reverse("flavor_object_api")
response = self.client.get(url)
self.assertEquals(response.status_codde, 200)
data = json.loads(response.content)
self.assertEquals(len(data), 1)
import json
from django.urls import reverse
from django.test import TestCase
from flavors.models import Flavor
class DjangoRestFrameworkTests(TestCase):
def setUp(self):
Flavor.objects.get_or_create(title="title1", slug="slug1")
Flavro.objects.get_or_create(title="title2", slug="slug2")
self.create_read_url = reverse("flavor_rest_api")
self.read_update_delete_url = reverse("flavor_rest_api", kwargs={"slug": "slug1"})
def test_list(self):
response = self.client.get(self.create_read_url)
self.assertContains(response, "title1")
self.assertContains(response, "title2")
def test_detail(self):
response = self.client.get(self.read_update_delete_url)
data = json.loads(response.content)
content = {"id": 1, "title": "title1", "slug": "slug1", "scoops_remaining": 0}
def test_create(self):
post = {"title": "title3", "slug": "slug3"}
response = self.client.post(self.create_read_url, post)
data = json.loads(response.content)
self.assertEquals(response.status_code, 201)
content = {"id": 3, "title": "title3", "slug": "slug3", "scoops_remaining": 0}
self.assertEquals(data, content)
self.assertEquals(Flavor.objects.count(), 3)
def test_delete(self):
response = self.client.delete(self.read_update_delete_url)
self.assertEquals(response.status_code, 204)
self.assertEquals(Flavor.objects.count(), 1)
https://martinfowler.com/articles/microservices.html
https://en.wikipedia.org/wiki/Representational_state_transfer
https://jacobian.org/2008/nov/14/rest-worst-practices/
'Django' 카테고리의 다른 글
Django Utils (0) | 2019.08.23 |
---|---|
REST API 이용하기 (0) | 2019.07.22 |
queryset (0) | 2019.07.15 |
Angular4 (0) | 2019.07.14 |
Class ListView() (0) | 2019.07.13 |