REST API에 대해서(2) 설계

정지은·2022년 12월 13일
0

이론

목록 보기
2/2

REST API를 만드는 방법에 대한 이론들을 정리해 보았다.


1. API의 목적

거칠게 요약하자면 '데이터를 주고받는 것'이다. 그 형태는 XML, JSON등 다양할 수 있지만 특정한 데이터를 전달하고 받는다는 전제에서는 벗어나지 않는다. 그렇다면 REST API를 설계할 때에는 이 데이터를 얼마나 정확히, 효율적으로 전달할 수 있을지를 고민해야 할 것이다.

2. 기본 구조

자원, 행위, 표현으로 나눌 수 있다. 또는 리소스, 메소드, 메시지라고도 한다.(REST API에 대해서(1))

예를 들어

        let fd = new FormData();

        fd.append('file', file);
        fd.append('image', image);
        fd.append('content', content);

        $.ajax({
            url: "/content/upload",
            data: fd,
            method: "POST",
            processData: false,
            contentType: false,
            success: function (data) {
                console.log("성공");
            },
            error: function (request, status, error) {
                console.log("에러");
            }
        })
// 이전 포스트에 적었던 예시 코드를 가져왔다.

다음과 같은 요청이 있다면, 전송되는 API의 형태는

HTTP POST , http://localhost/content/upload

{  

   {  
         "file" : file,
         "image" : image,
         "content" : content

   }

}

다음과 같은 형태가 될 것이다. 즉 이 코드에서의 자원은 URL(/content/upload), 행위는 POST, 표현은 fd데이터 객체에 대응된다.

3. 구현

구현 프레임워크에 따라 세부 내용은 다르지만, 다음과 같은 형태로 구성된다. 자세한 구축방법은 나중에 따로 포스트를 작성하도록 하고, 여기서는 대략적인 구조만 정리한다.

  1. 모델(데이터 객체) 생성
class User(AbstractBaseUser, PermissionsMixin, TimestampedModel):
    
    username = models.CharField(max_length=255, unique=True)
    email = models.EmailField(db_index=True, unique=True)
    phone_number = models.CharField(max_length=255)
    is_active = BooleanField(default=True)
    is_staff = BooleanField(default=False)
    
    ... (후략)
  1. 모델 간의 관계 정의
    (필요 시 *직렬화)
class TimestampedModel(models.Model):
	
    # 생성된 날짜를 기록
    created_at = models.DateTimeField(auto_now_add=True)
    # 수정된 날짜를 기록
    updated_at = models.DateTimeField(auto_now=True)
    
    ...(후략)
  1. 메소드 요청을 처리하는 컨트롤러 생성
class RegistrationAPIView(APIView):
    permission_classes = (AllowAny,) # allowany : 인증 여부에 상관 없이 뷰 호출 허용
    serializer_class = RegistrationSerializer # serializers.py에서 만든 클래스
    renderer_classes = (UserJSONRenderer,) # renderers.py에서 만든 클래스
    
    def post(self, request):
        # client가 요청한 데이터(request.data)를 받아와 직렬화(self.serializer_class(data=user)하고
        # 유효성(serializer.is_valid)을 확인해서 저장(serializer.save( ))
        
        user = request.data
        
        serializer = self.serializer_class(data=user)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_201_CREATED)
        
        ...(후략)

Serialize(직렬화)란?
객체를 데이터스트림으로 만드는 것이다. 반대로 스트림을 객체로 만드는 것을 역직렬화라고 한다. 멤버들마다 다른 값을 가지는 필드들을 손실 없이 주고받기 위해 사용한다. 예를 들어, 참조 데이터(Reference Type)은 그대로 전송했을 때에 값이 변할 수 있으므로, 직렬화를 하면 값 데이터(Value Type)로 변경이 된다.
모든 멤버가 같은 수행을 하는 메소드는 직렬화의 대상이 아니다.

4. 설계 원칙

url

  • 주소가 /로 끝나지 않게 한다.
  • '_'나 '-'의 사용을 최소화하되, 꼭 써야 한다면 '-'를 쓴다.
  • 소문자를 사용한다. NoticePage(x) notice-page(o)
  • 무슨 method를 사용했는 지 url로 확인할 수 없게 한다.

http status

  • 성공하면 2xx을 리턴하고, 실패하면 4xx을 리턴한다.(의미에 맞는 코드를 리턴해야한다.)
  • 5xx은 사용자에게 리턴해서는 안 된다. 서버 api는 모든 발생가능한 에러를 핸들링해야한다.
profile
Steady!

0개의 댓글