logo

Backend에서 API Response가 snake_case 경우엔 ?

javascript · 2021년 6월 11일 · 12 min read

프론트엔드 개발자의 경우,
가끔 백엔드의 API Response 값이 snake_case일 경우 어떻게 관리할 지에 대해 고민에 빠지게 됩니다.

저도 오늘 같은 상황을 겪게 되었는데,
이번엔 네이밍 컨벤션을 맞춰주기로 했습니다.

컨벤션을 맞추는 데에는 여러가지 방법이 있겠지만,
고민 끝에 저는 axiosinterceptor를 통해 해결을 해보았습니다.

1. 적용하기

전체적인 프로세스는 두 가지입니다.
하나는 공용으로 사용하는 instance에 interceptor를 붙이는 것,
하나는 넘겨받은 object의 key들을 CamelCase로 변경하는 함수를 작성하는 것이 되겠습니다.

먼저 interceptor를 붙여봅시다.

import axios from 'axios'

const client = axios.create({
  withCredentials: true,
})

client.interceptors.response.use((response) => {
  response.dataOriginal = JSON.parse(JSON.stringify(response.data))

  return response
})

export default client

혹시 모를 경우를 위해 오리지널 데이터를 따로 복제해둡시다.
이번엔 object의 key들을 CamelCase로 변경하는 함수를 작성해보겠습니다.

export const objectKeysToCamelCase = (ob = {}, isDeep = true) => {
  return Object.entries(ob).reduce((acc, [key, value]) => {
    const keyComputed = key.replace(/(_.?)/g, (matches) => matches[1].toUpperCase())

    let result

    if (isDeep === false || !value || typeof value !== 'object') {
      result = value
    } else if (Array.isArray(value)) {
      result = value.map((item) => objectKeysToCamelCase(item, isDeep))
    } else {
      result = objectKeysToCamelCase(value, isDeep)
    }

    acc[keyComputed] = result

    return acc
  }, {})
}

저는 유틸리티성 함수들을 따로 모아 관리하고 있어서 export가 포함되어있는데,
만약 하나의 파일에서 진행하신다면, 굳이 넣지 않으셔도 됩니다.

함수를 조금 설명하자면, API Response 값의 경우 대부분 여러 depth가 존재할 텐데, 이를 위해 재귀함수로 구성하였습니다.

만약 2번째 파라미터인 isDeep이 참이라면,
depth 1 뿐만 아니라 하위 depth까지 object가 존재하는지 탐색하고 key의 컨벤션들을 CamelCase로 변환시켜줍니다.

반대로 거짓일 경우엔 depth 1의 key 값들만 변환시켜주겠지요 ?

이렇게 네이밍컨벤션을 변환해주는 함수를 만들었다면, 아래와 같이 적용시켜줍시다.

import axios from 'axios'

import { objectKeysToCamelCase } from '../util'

const client = axios.create({
  withCredentials: true,
})

client.interceptors.response.use((response) => {
  response.dataOriginal = JSON.parse(JSON.stringify(response.data))

  response.data = objectKeysToCamelCase(response.data)

  return response
})

export default client

그 후 확인해보면,

ex_screenshot"

적용이 잘 된 것을 확인해볼 수 있습니다.

하지만 여기서 뭔가 찜찜한 기분이 드는데,

퍼포먼스에 대한 이슈입니다.

아무래도 모든 요소의 key와 value를 탐색하고, 비교 한 뒤 새로운 객체를 생성하는데, 걱정이 안 될 수가 없습니다.

그래서 한번 ... 테스트를 시도해보았습니다.

2. 퍼포먼스 테스트

import axios from 'axios'

import { objectKeysToCamelCase } from '../util'

const client = axios.create({
  withCredentials: true,
})

client.interceptors.response.use((response) => {
  console.time()

  response.dataOriginal = JSON.parse(JSON.stringify(response.data))

  response.data = objectKeysToCamelCase(response.data)

  console.timeEnd()

  return response
})

export default client

단순히 response가 도착한 후 interceptor가 받아 들일 때부터 넘겨줄 때까지의 시간을 재어봤는데요.

ex_screenshot"

다행히도 이 과정에 0.017초 가량 소요된 것을 알 수 있었습니다.

관련 포스트
post image
Vue 3 입문기
Vue의 메인 버전이 3가 된지 꽤 됐다. 주로 Nuxt 환경에서 작업해왔기 때문에, 그리고 아직 Vue 3를 채용한 Nuxt 3가 RC 단계이기 때문에 Product에 적용하기에는 어려움이 있었다. 그래서 궁금하고 심심하던 참에 간단한 Todo Applink icon을 만들어봤다.
javascript·2022년 9월 28일·7 min read
post image
marked renderer custom 하기
현록을 개발하면서 티스토리에 있던 포스트들을 markdown으로 변환하여 올리고 있는데, 간혹 이미지 가로 사이즈가 viewport width보다 크면 overflow되는 현상이 있었습니다. 사실 css로 해결하였지만, styled-components 환경에서 nesting하는 것을 꺼리기도 하고, marked에서 직접 inline style을 넣는 방법이 궁금하기도 해서 찾아보았습니다.
javascript·2022년 9월 12일·4 min read
post image
가독성 있게 상수 넣기
오늘 회사 동료의 PR 리뷰 과정에서 좋은 기능을 공유해주셔서 TIL로 남겨봅니다. 아래와 같이 상수에 언더바(_)로 콤마처럼 구분을 시켜줄 수 있습니다. 앞으로 깔끔하고 좋은 코드를 작성하기 위해 자주 사용해야겠습니다 :)
javascript·2022년 9월 6일·2 min read
post image
TS에서 generic optional 하게 설정하기
오늘 next에서 `getStaticProps`와 `getLayout` 패턴을 함께 사용할 때, typescript generic을 넘겨주는 작업을 하고 있었는데, 기본값이 없다보니 기존 코드에 에러가 발생했었다. 이를 해결하기 위해 찾아보니 단순히 아래 예시처럼 `= {}`을 추가해주면 해결된다고 한다.
javascript·2022년 8월 24일·2 min read
post image
Promise 다루기 (feat. 병렬실행, 순차실행)
오늘은 Promise를 통해 구문을 동기 처리 할 때, 여러 Promise들을 다루는 법을 소개해보겠습니다. Javscript를 작성하다 보면, 가끔 여러 Promise들을 다룰 때가 있습니다. 필자도 Nodejs 서버에서 동시에 여러 쿼리를 실행할 때 자주 마주쳤었는데요. 오늘은 어떻게 하면 Promise들을 유연하게 다룰 수 있는지 알아보겠습니다. 시작하기 앞서, 네 가지 Promise를 선언하고, 그들을 하나의 Array에 묶어보겠습니다.
javascript·2021년 4월 25일·11 min read