Get request with body

회사에서 주소검색API를 만들었다.
나혼자 여러모로 테스트도 다 해보고 실제 붙여서 클라이언트에서도 호출하는 테스트를 다 마치고 실제 사용도 하고 있는데 ..

갑자기 다른 파트 개발자분이 내 API에서 에러를 뱉어낸다고 하네?! ㅜㅜ

찾아본 결과 GET request를 했는데 헤더에 Content-Type: application/json을 보낸 차이로 400 Bad Request 에러를 리턴했다.

아래는 경우에 따른 테스트 결과다.

GET 방식은 Content-Type을 명시하지 않고 URI로 데이터 처리하는게 기본 방식이다. 문제없이 200을 리턴한다.

Content-Type 헤더없이 URI로 데이터 전송

###
GET localhost:8088/api/search?keyword=여의도공원&limit&page=1
Response
GET http://localhost:8088/api/search?keyword=%EC%97%AC%EC%9D%98%EB%8F%84%EA%B3%B5%EC%9B%90&limit=&page=1

HTTP/1.1 200 OK
Date: Mon, 30 Aug 2021 06:28:12 GMT
Server: Apache/2.4.29 (Ubuntu)
Cache-control: no-store, max-age=0, no-cache
Debugbar-Time: 1630304894
Debugbar-Link: http://localhost:8088/?debugbar_time=1630304894
Content-Length: 1480
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json; charset=UTF-8

{
  "total": 1,
  "count": 1,
  "data": [
    {
      ....
    }
  ],
  "pagination": {
    "total": 1,
    "perPage": 5,
    "pageCount": 1,
    "currentPage": 1,
    "prev": null,
    "next": null,
    "first": 1,
    "last": 1
  }
}

Response code: 200 (OK); Time: 1670ms; Content length: 1308 bytes

Content-Type을 json으로 보냈는데 400 오류가 났다.
이 API는 CodeIgniter4를 사용해서 만들었는데 해당 프레임워크에서는 데이터 전송 시 Content-Type: application/json 헤더가 명시되어 있으면 body에 있는 데이터를 처리한다.
그래서 query로 keyword 데이터를 보냈음에도 body에 데이터가 없어서 keyword 데이터없음 에러를 리턴했다.

Content-Type 작성하고 URI로 데이터 전송

###
GET localhost:8088/api/search?keyword=여의도공원&limit&page=1
Content-Type: application/json
Response
GET http://localhost:8088/api/search?keyword=%EC%97%AC%EC%9D%98%EB%8F%84%EA%B3%B5%EC%9B%90&limit=&page=1

HTTP/1.1 400 Bad Request
Date: Mon, 30 Aug 2021 06:28:24 GMT
Server: Apache/2.4.29 (Ubuntu)
Cache-control: no-store, max-age=0, no-cache
Debugbar-Time: 1630304906
Debugbar-Link: http://localhost:8088/?debugbar_time=1630304906
Content-Length: 132
Connection: close
Content-Type: application/json; charset=UTF-8

{
  "status": 400,
  "error": 400,
  "messages": {
    "error": "{\"keyword\":\"The keyword field is required.\"}"
  }
}

Response code: 400 (Bad Request); Time: 1412ms; Content length: 132 bytes

GET 메서드를 사용할 때 경우에 따라서 json 데이터를 보내고 싶을 때도 있으니 Content-Type: application/json 헤더를 명시하고 아래처럼 body에 데이터를 넣어서 호출하면 오류없이 리턴된다.

Content-Type 작성하고 body로 데이터 전송

###
GET localhost:8088/api/search
Content-Type: application/json

{
  "keyword": "여의도공원",
  "limit": null,
  "page": 1
}
Response
GET http://localhost:8088/api/search

HTTP/1.1 200 OK
Date: Mon, 30 Aug 2021 06:28:29 GMT
Server: Apache/2.4.29 (Ubuntu)
Cache-control: no-store, max-age=0, no-cache
Debugbar-Time: 1630304911
Debugbar-Link: http://localhost:8088/?debugbar_time=1630304911
Content-Length: 1480
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json; charset=UTF-8

{
  "total": 1,
  "count": 1,
  "data": [
    {
      ...
    }
  ],
  "pagination": {
    "total": 1,
    "perPage": 5,
    "pageCount": 1,
    "currentPage": 1,
    "prev": null,
    "next": null,
    "first": 1,
    "last": 1
  }
}

Response code: 200 (OK); Time: 1711ms; Content length: 1308 bytes

CI외에도 다른 서버, 클라이언트들이 GET에서 body를 보내는 경우

  • POST로 인식을 하거나
  • 오류를 리턴하거나
  • 그냥 GET에서도 body를 처리해주거나

하는 경우가 있으니 사용하는 환경이나 협업하는 동료와 규칙을 정해서 개발하는 것이 좋겠다.

참고 블로그

javascript json array copy value not ref.

array 복사는 간단하게 slice로.
https://www.w3schools.com/jsref/jsref_slice_array.asp

let dataA = {
    label1: 'test1',
    label2: 'test2',
}

let dataB = dataA
dataB.label1 = 'test0'

위와 같이 했을 때 dataB는 레퍼런스 참조를 해서 dataA.label1도 test0으로 변경된다.
말 그대로 값만 복사해서 따로 데이터를 처리하고 싶을 때는 JSON을 이용한다.

let dataB = JSON.parse(JSON.stringify(dataA))
dataB.label1 = 'test0' // dataB.label1만 변경된다.