ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [API] 2. RESTFUL API - RESPONSE STATUS CODE + 객체 활용 응답 처리(데코레이터, 클래스)
    HTTP 2021. 11. 1. 17:02

    이전글 -

    2020.11.01 - [Web/HTTP] - [API] 1. RESTful API란?

    코드

    status = {
        "OK": 200,  # GET - DATA OR EMPTY LIST
        "CREATED": 201,  # POST,
        "ACCEPTED": 202,  # POST - ASYNC
        "NO CONTENT": 204,  # DELETE, PUT
        "BAD REQUEST": 400,  # GENERAIL FAIL - CLIENT ERROR
        "NO AUTH": 401,  # LOGIN NEEDED
        "FORBIDDEN": 403,  # ADMIN ONLY
        "NOT FOUND": 404,  # NOT FOUND BY IDENTIFIER
        "SEVER ERROR": 500,  # SEVER ERROR
    }
    
    message = {
        "kr": {
            "OK": "성공",  # GET - DATA OR EMPTY LIST
            "CREATED": "생성",  # POST,
            "ACCEPTED": "요청 성공",
            "NO CONTENT": "요청 성공",  # DELETE, PUT
            "BAD REQUEST": "잘못된 요청입니다.",  # GENERAIL FAIL - CLIENT ERROR
            "NO AUTH": "로그인이 필요합니다.",  # LOGIN NEEDED
            "FORBIDDEN": "접근 권한이 없습니다.",  # ADMIN ONLY
            "NOT FOUND": "원하시는 데이터를 찾지 못했습니다.",  # NOT FOUND BY IDENTIFIER
            "SEVER ERROR": "죄송합니다. 다음에 다시 시도해주세요.",  # SEVER ERROR
        },
        "en": {
            "OK": "Success",  # GET - DATA OR EMPTY LIST
            "CREATED": "Created",  # POST
            "ACCEPTED": "Request accepted",
            "NO CONTENT": "Request has succeeded",  # DELETE, PUT
            "BAD REQUEST": "BAD REQUEST",  # GENERAIL FAIL - CLIENT ERROR
            "NO AUTH": "Please login first",  # LOGIN NEEDED
            "FORBIDDEN": "No permission",  # ADMIN ONLY
            "NOT FOUND": "Couldn't find what you want",  # NOT FOUND BY IDENTIFIER
            "SEVER ERROR": "Oops, something went wrong",  # SEVER ERROR
        },
    }
    # core/response.py
    from core.constants import response
    
    def return_404_for_no_auth(f):
        def wrapper(*args, **kwargs):
            user = None
            # ..... 유저 세션 체크 로직
    		if user is None: 
                response = CustomeResponse()
    			return response.send(response_type="NO_AUTH")
            return f(*args, **kwargs, auth_user=user)
            
        # ..... wrapper 관련 코드
        return wrapper
    
    
    def return_500_for_sever_error(f):
        def wrapper(*args, **kwargs):
            try:
                return f(*args, **kwargs)
            except:
    		    # ..... 에러 처리 관련 코드
                response = CustomeResponse()
                return response.send(
                    response_type="SEVER_ERROR",
                )
        
        # ..... wrapper 관련 코드
        return wrapper
    
    
    class CustomeResponse:
        headers = {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Headers": "*",
            "Access-Control-Allow-Credentials": "True",
        }
    
        def send(
            self,
            result=None,
            response_type=None,
            lang="en",
            additional_message=None,
        ):
    
            status = response.status[response_type]
            message = response.message[lang][response_type]
    
            if additional_message is not None:
                message += f"({additional_message})"
    
            response_body = {"result": result, "message": message}
    
            json_encode = json.JSONEncoder().encode
            return Response(
                json_encode(response_body),
                status=status,
                headers=self.headers,
                mimetype="application/json",
            )
    from core.response import (
        CustomeResponse,
        return_500_for_sever_error,
        return_404_for_no_auth,
    )
    
    @api.route("/<int:id_>")
    @api.param("id_", "The action identifier")
    class Action(Resource, CustomeResponse):
        @return_500_for_sever_error
        def get(self, id_):
            if action := get_action(id_):
                return self.send(response_type="SUCCESS", result=action)
            return self.send(response_type="NOT_FOUND")
    
        @api.doc("update action name")
        @api.expect(parser_post, parser_auth)
        @return_404_for_no_auth
        @return_500_for_sever_error
        def put(self, id_, **kwargs):
            if get_action(id_):
                if kwargs["auth_user"].is_admin():
                    args = parser_post.parse_args()
                    update_action(id_, args["name"])
                    return self.send(response_type="NO_CONTENT")
                return self.send(response_type="FORBIDDEN")
            return self.send(response_type="NOT_FOUND")
    
        @api.doc("delete an action")
        @api.expect(parser_auth)
        @return_404_for_no_auth
        @return_500_for_sever_error
        def delete(self, id_, **kwargs):
            if get_action(id_):
                if kwargs["auth_user"].is_admin():
                    delete_action(id_)
                    return self.send(response_type="NO_CONTENT")
                return self.send(response_type="FORBIDDEN")
            return self.send(response_type="NOT_FOUND")

    GET - 리소스 조회

    • 리소스들을 전체를 가져오거나 특정 조건(필터)에 맞춰서 리소스들을 반환한다.
    • 데이터가 없는 경우에는 빈 배열([])를 반환한다.
    • 데이터가 있던 없던 성공 시 200
    • 필수 조건 또는 조건 값 등의 맞지 않는 경우 400
    • 특정 Identifier(식별자)로 조회하는 경우에 없으면 404 (NOT FOUND)
    • 서버 에러 500

    POST - 새로운 리소스 생성

    • 새로운 리소스를 생성한다.
    • 데이터가 정상적으로 생성 경우에는 리소스 아이디를 반환한다.
    • 데이터가 정상적으로 생성되면 201, 비동기 작업 시 202
    • 생성시 필요한 데이터가 없는 경우, 유니크한 값이 이미 존재하는 경우 등 400 (클라이언트에서 다른 값을 보내줘야함)
    • 서버 에러 500

    PUT - 이미 존재하는 리소스 업데이트 

    • 기존의 리소스를 업데이트한다.
    • 특정 Identifier(식별자)로 없으면 404 (NOT FOUND)
    • 기존에 데이터에 식별자 제외 전체를 업데이트 하는게 기본/ 예외는 있을 수 있음
    • 업데이트 성공 시 204 - NO CONTENT 업데이트 실패시 400
    • 서버 에러 500
    • GET POST DELETE 으로는 어울리지 않는 작업들은 PUT으로 요청

    DELETE - 이미 존재하는 리소스를 삭제

    • 기존의 리소스를 삭제한다.
    • 특정 Identifier(식별자)로 없으면 404 (NOT FOUND)
    • 업데이트 성공 시 204 - NO CONTENT
    • 서버 에러 500

    'HTTP' 카테고리의 다른 글

    사용자 인증 Cookie, Session, JWT  (0) 2020.12.30
    [API] 1. RESTful API란?  (0) 2020.11.01
Designed by Tistory.