Response 구조화하기

kukjunLEE·2023년 7월 30일
2

Tutorial

목록 보기
2/2
post-thumbnail

본 내용은 Backend와 Frotnend가 Rest api를 이용해서 Frontend와 통신할 때, 서로의 정보를 더 잘 이해하기 위해서 응답의 형태를 구조화 하는 내용과 예시를 담고 있습니다.




Response 구조화의 필요성


Frontend와 Backend에서 각각 데이터를 보내고 받는 요청에 대해서 API 명시를 하고 사용하고 있습니다.


하지만 모든 Response에서 공통적으로 들어가야 하는 값을 사용하거나, Error가 발생했을 때, 일관되게 Frontend 가 처리할 수 있도록 하기 위해서는 Response를 구조화 할 필요성이 있습니다.



구조화를 위한 방식


Backend에서 API를 개발하다보면 다들 Response를 만들어서 제공하고 있습니다. 하지만 Frontend를 고려하지 않는 방식으로 개발하게 된다면 Frontend가 매번 API구조를 확인하고 이를 적용하는 일을 반복해야 합니다.

문제가 되는 예시

{
  "id": 1,
  "name": "kukjun"
}

만약 유저를 조회하는 부분을 실행시켰다고 했을 때, 지금과 같이 Response의 Body를 그대로 만들어주는 경우가 있습니다.

예외에 대한 부분은 다음과 같습니다.

{
  "statusCode": 404,
  "errorMessage": "USER NOT FOUND"
}

이러한 방식은, 본인이 Frontend, Backend를 둘 다 개발한다면 크게 문제가 되지 않습니다. 하지만 만약 협업을 한다고 생각하면, 내가 만든 모든 Response와 Error에 대해서 Frontend가 모두 처리해줘야 할 것입니다. 특히, Error의 경우는 사용자에게 보여줘야 한다면, errorMessage를 맵핑에서 보여줘야겠죠. 🥹

구조화 예시

{
  "RequestCode": "REQ-0001",
  "ResponseCode": "User-P-0001",
  "DataResponse": {
    "id": 1,
    "name": "kukjun"
  },
  "timestamp": 1242147812,
  "requestUrl": "/api/auth/user",
  "requestMethod": "POST",
}
{
  "errorCode": "USER-001",
  "errorMessage": "User Not Found",
  "errorObject": {
    "require": {
      "A": "not found"
    }
  }
}

지금과 같이 설정한다면, ResponseCode, ErrorCode에 Frontend에서 에러를 처리해줄 수 있을 것입니다. 👍🏼

이제, 이러한 구조가 각각 어떤 의미를 가지는지 설명하겠습니다.





Response 구조화 예시



CommonResponse

CommonResponse라고 하는 것을 사용해서, 모든 Response를 일치시킨다고 가정하면 다음과 같은 형태로 예시를 만들 수 있습니다.


CommonResponse(Response)

  • RequestCode
  • ResponseCode
  • DataResponse
  • timestamp
  • requestUrl
  • requestMethod
  • …etc

CommonResponse에 대해 실제 값이 들어가는 형태로 표현하면 다음과 같습니다.


Example - CommonResponse

{
	"RequestCode": "REQ-0001",
	"ResponseCode": "User-P-0001",
	"DataResponse": {
		"id": 1,
		"name": "kukjun"
	},
	"timestamp": 1242147812,
	"requestUrl": "/api/auth/user",
	"requestMethod": "POST",
}
  • RequestCode : 들어온 요청이 어떤 것이었는지 Code로 표현합니다.
  • ResponseCode : 지금 내보내는 요청이 어떤 것인지 Code로 표현합니다.
  • DataResponse : 실제로 Data를 제공합니다.
  • timestamp : 요청의 응답 시간을 제공합니다.
  • requestUrl : 요청받은 URL을 제공합니다.
  • requestMethod : 요청받은 Method를 제공합니다.


DataResponse

DataResponse는 실제로 요청에 대한 응답 값들이 들어가는 영역입니다.

그냥 응답 값을 넣는 경우에는 문제가 되지 않습니다만, 에러가 발생해서 문제가 있음을 반환해야 할 경우, 즉 Error정보를 반환하는 Response에 경우에는 구조화 할 필요성이 있습니다.


제가 생각하는 ErrorDataResponse는 다음과 같습니다.

ErrorDataResponse(DataResponse)

  • errorCode
  • errorMessage
  • errorObject

ErrorDataResponse에 대해 실제 값이 들어가는 형태로 표현하면 다음과 같습니다.



Example - ErrorDataResponse

{
	"errorCode": "USER-0001",
	"errorMessage": "User Not Found",
	"errorObject": {
		"require": {
			"A": "not found"
		}
	}
}
  • errorCode : frontend에서 추가적으로 처리할 수 있도록 에러의 정보를 담습니다.
  • errorMessage : frontend에서 따로 처리하지 않는 경우에도 message를 반환할 수 있도록 message를 제공합니다.
  • errorObject : 해당 에러 해결을 위해 추가적으로 필요한 정보에 대해서 제공해줄 수 있도록 합니다.




Wasabi Response 구조화


Wasabi는 학생들과 함께하는 프로젝트이고, 내용이 복잡하지 않습니다.
Wasabi는 여기 있어요😃

따라서 구조화를 하되 최대한 단순하게 만들어서 작업하려고 합니다.

CommonResponse

CommonResponse(Response)

  • DataResponse
  • timestamp

Example - CommonResponse

{
	"DataResponse": {
		"id": 1,
		"name": "kukjun"
	},
	"timestamp": 1242147812,
}

DataResponse

ErrorDataResponse(DataResponse)

  • errorCode
  • errorMessage

Example - ErrorDataResponse
{
"errorCode": "USER-001",
"errorMessage": "User Not Found",
}




🚨 주의사항


사실 모든 Error는 추상적이어야 합니다. 사용자 편의성을 위해서 제공하는 몇몇 예외를 제외하고는 외부에서 서버 및 데이터베이스의 존재 여부 등 정보를 최대한 감춰서 제공해야 합니다.

예를 들면 Login을 할때, Id, Password를 입력한다고 가정하면 ID가 틀린 경우와, ID는 맞고 Password만 틀린 경우를 모두 같은 예외를 발생시켜야 한다는 것입니다.
물론, 이러한 처리는 당연하게 하겠지만, 생각보다 서비스에서 감춰야 하는 내용은 아주 많습니다. 그래서 어떤 요청이 왔을 때, 정상적인 사용을 제외한 모든 요청에 대해서는 응답을 최소화해서 제공해야 합니다.

물론 내부 디버깅을 위한 로깅은 구체적이면 좋지만요! 😃




profile
Backend Developer

1개의 댓글

comment-user-thumbnail
2023년 7월 30일

이런 유용한 정보를 나눠주셔서 감사합니다.

답글 달기