Backend 17
Postman으로 API 요청의 모든 것을 실험하기
API를 만들었는데 브라우저 주소창만으로는 왜 충분히 테스트할 수 없는지 모르겠다.
근거 · 교안 p104-p114
1장: 주소창의 한계: 브라우저가 모든 요청을 보낼 수 없는 이유
솔라의 손가락이 키보드 위에서 경쾌하게 멈췄다. 방금 막 완성한 사용자 정보 수정 API 코드를 만족스럽게 바라보던 참이었다. 이제 이 코드가 의도대로 잘 작동하는지 확인해 볼 차례였다.
“좋았어. 이제 테스트만 해보면 되겠다.”
솔라는 습관처럼 새 브라우저 탭을 열었다. API 명세서에는 사용자 정보를 수정하려면 PUT이라는 메서드를 사용해서 특정 주소로 요청을 보내야 한다고 적혀 있었다. 간단한 일이라고 생각했다.
“언니, 나 방금 만든 API 테스트해볼래. 그냥 늘 하던 대로 브라우저 주소창에 주소 치면 되겠지?”
옆에서 조용히 자신의 노트북을 보던 루나가 솔라 쪽으로 고개를 돌렸다.
“그래? 어떻게 테스트할 건데?”
“응. 사용자 정보를 수정하는 거니까, 서버에 데이터를 보내야 하잖아. API 문서에는 PUT 메서드를 쓰라고 되어 있어. 그러니까… 주소창에 ‘PUT’이라고 쓰고, 주소를 입력하면 되지 않을까?”
솔라는 자신만만하게 키보드에 손을 올렸다. 그리곤 주소창에 또박또박 타이핑하기 시작했다.
PUT localhost:8080/users/1
솔라가 엔터 키를 누르는 순간, 화면에는 예상과 전혀 다른 결과가 나타났다. 사용자가 성공적으로 수정되었다는 메시지 대신, ‘PUT localhost:8080/users/1’이라는 문구가 담긴 구글 검색 결과 페이지가 떴다.
“어?”
솔라의 미간이 살짝 찌푸려졌다. “왜 검색이 되지? 요청을 보내야 하는데.”
솔라는 다시 시도했다. 이번에는 ‘PUT’이라는 단어를 빼고 localhost:8080/users/1 주소만 입력했다. 엔터를 누르자, 이번에는 텅 빈 화면에 오류 메시지가 희미하게 나타났다. 솔라는 곧장 자신의 개발 서버 로그를 확인했다.
Request Received: GET /users/1
“아니, 이것도 아니네. 서버 로그에는 GET 요청이 왔다고 찍혔어. 데이터를 수정하라고 PUT 요청을 보내야 하는데, 왜 마음대로 GET 요청을 보내는 거야?”
솔라는 혼란스러워하며 의자 등받이에 몸을 기댔다. 분명 주소창에 정확한 목적지를 알려주었는데, 브라우저는 완전히 제멋대로 움직이는 것 같았다.
루나가 솔라의 화면과 서버 로그를 잠시 들여다보더니, 차분하게 물었다.
“우리가 평소에 브라우저 주소창을 쓸 때를 생각해 봐. 네이버나 구글 주소를 입력하고 엔터를 치면, 브라우저가 뭘 하지?”
“음… 그 주소에 있는 웹 페이지를 화면에 보여주지. 즉, 서버에서 웹 페이지 데이터를 가져오잖아.”
“맞아. 가져오지.”
루나는 짧게 대답하고는 솔라가 스스로 다음 생각을 이어가도록 기다렸다. 솔라는 잠시 허공을 응시했다. ‘가져온다’. 그 단어가 머릿속을 맴돌았다.
“잠깐만… 그러면 내가 주소창에 어떤 주소를 입력하든, 브라우저는 무조건 그 주소에 있는 데이터를 ‘가져오려고’만 하는 건가? 내가 ‘이 데이터를 저장해 줘’라거나 ‘이 데이터를 수정해 줘’라고 아무리 말하고 싶어도, 브라우저는 그냥 ‘알았어, 거기 가서 뭐든 가져올게’라고만 알아듣는 거야?”
솔라는 자신의 가설을 검증하려는 듯 다시 브라우저 창을 뚫어져라 쳐다봤다. 주소창, 뒤로 가기 버튼, 새로고침 버튼. 그 어디에도 ‘수정해 줘(PUT)’나 ‘새로 만들어 줘(POST)’ 같은 명령을 내릴 만한 곳은 보이지 않았다. 오직 주소를 입력하고 ‘이동’하는 기능만 있을 뿐이었다.
“아…!”
마침내 무언가 깨달았다는 듯 솔라의 입에서 작은 탄성이 터져 나왔다.
“주소창은 그냥 내비게이션 같은 거구나. 목적지 주소를 찍으면 길을 찾아서 ‘데려다주는’ 역할만 하는 거야. 차에 탄 내가 ‘여기 편의점에 물건 좀 맡겨줘!’라고 외쳐도, 내비게이션은 그 말을 알아듣지 못하고 그냥 목적지로 직진만 하는 것처럼.”
솔라는 방금 전 자신의 시도가 왜 실패했는지 완벽하게 이해했다. 브라우저 주소창은 모든 종류의 요청을 보내는 만능 도구가 아니었다. 그 역할은 단 하나, 사용자가 입력한 주소(URL)의 자원을 ‘가져오는 것(GET)’에 특화되어 있었다. 다른 복잡한 임무를 수행할 능력 자체가 없었던 것이다.
“결국 브라우저 주소창으로는 GET 요청밖에 못 보내는 거였어. 내가 아무리 PUT이라고 타이핑해 봤자 브라우저는 그걸 명령어로 인식하지 못하고 그냥 검색할 단어로 취급해 버린 거고.”
문제가 명확해지자 답답함은 사라졌지만, 동시에 새로운 의문이 고개를 들었다.
솔라는 다시 키보드 앞으로 몸을 당겨 앉으며 말했다.
“좋아, 이제 브라우저 주소창이 ‘가져오기’ 전문이라는 건 알겠어. 그럼 도대체 POST나 PUT, DELETE 같은 다른 요청들은 다들 어떻게 테스트하고 있는 거지? 뭔가 다른 특별한 방법이라도 있는 거야?”
2장: Postman이 필요한 이유: HTTP 요청의 모든 요소를 해체하다
솔라의 질문에 루나는 대답 대신 자신의 노트북 화면을 솔라 쪽으로 돌려주었다. 화면에는 언뜻 보기에 브라우저와 비슷하지만 어딘가 훨씬 더 복잡하고 전문적으로 보이는 애플리케이션이 띄워져 있었다. 익숙한 주소창 같은 것이 상단에 있었지만, 그 주변으로 여러 개의 탭과 버튼, 정체 모를 패널들이 가득했다.
솔라는 화면을 가만히 들여다보았다. 브라우저의 단순함과는 거리가 멀었다. 마치 비행기 조종석의 계기판을 보는 기분이었다.
“이건 뭐야? 무슨 개발 툴이야?”
“Postman.”
루나의 짧은 대답에 솔라는 고개를 갸웃했다. “포스트맨? 우편배달부? 이름 한번 특이하네. 이것도 브라우저 같은 거야? 근데 왜 이렇게 복잡해 보여? 그냥 좀 더 예쁘게 꾸며놓은 브라우저 탭 같은데…”
솔라의 시선은 여전히 화면 상단의 주소창에 꽂혀 있었다. 어차피 주소를 입력하고 보내는 거라면, 브라우저와 본질적으로 다를 게 없다고 생각했다.
루나는 솔라의 혼잣말을 들으며 마우스 커서를 움직였다. 그리고는 아무 말 없이 한 곳을 가리켰다. 주소창 바로 왼쪽이었다.
GET 이라고 쓰인 초록색 버튼이 있었다.
“저 버튼, 한번 눌러볼래?”
솔라는 의아해하며 루나의 노트북에 다가가 버튼을 클릭했다. 그러자 GET 아래로 긴 목록이 주르륵 펼쳐졌다.
GET
POST
PUT
PATCH
DELETE
...
솔라의 눈이 동그래졌다. POST, PUT, DELETE. 방금 전까지 자신이 브라우저 주소창에 입력하며 씨름했던 바로 그 명령어들이었다. 브라우저에서는 그저 무시당했던 단어들이, 여기서는 마치 레스토랑 메뉴판처럼 선택 가능한 옵션으로 버젓이 존재하고 있었다.
“잠깐만… 여긴… 요청 방식을 내가 직접 ‘선택’할 수 있네?”
루나는 이번엔 커서를 주소창 아래에 있는 여러 탭으로 옮겼다. Params, Authorization, Headers, Body.
솔라는 ‘Body’라는 단어를 보고 숨을 멈췄다. API 명세서에서 분명히 봤던 단어였다. 사용자 정보를 수정하려면 ‘Body’에 수정할 데이터를 담아서 보내라고 되어 있었다. 하지만 브라우저에는 도무지 그 ‘Body’에 데이터를 담아 보낼 방법이 없었다. 마치 편지지는 있는데 편지 봉투가 없는 상황 같았다.
“와… 여기 봐. 헤더(Headers)도 따로 설정할 수 있고, 바디(Body)도 따로 입력하는 칸이 있어.”
솔라는 비로소 Postman 화면의 전체적인 구조를 깨닫기 시작했다. 이것은 단순히 목적지 주소를 입력해 ‘이동’하는 도구가 아니었다. 서버에 보낼 ‘요청’이라는 하나의 꾸러미를 부품별로 조립하는 거대한 작업대였다.
솔라는 의자에서 벌떡 일어나 손가락으로 화면을 짚어가며 외쳤다.
“알겠다! 브라우저 주소창은 그냥 ‘어디로 갈지(URL)’만 알려주는 편도 티켓 같은 거였어. 목적지에 ‘가져오기(GET)’ 외에는 다른 방법으로 갈 수도 없고, 짐(Body)을 들고 탈 수도 없었지. 그런데 이건 달라!”
솔라의 목소리에 흥분이 실렸다.
“이건 마치 소포를 보내는 것과 같아. 먼저 배송 방식을 정하고(메서드 선택: GET, POST…), 받는 사람 주소(URL)를 쓰고, 내용물이 무엇인지(헤더: Content-Type), 그리고 상자 안에 넣을 물건(바디)까지 내가 하나하나 전부 정해서 포장할 수 있는 거야. 이건… 요청 조립 도구였어!”
‘요청 조립 도구.’ 솔라는 자신이 방금 뱉은 말이 이 복잡한 화면의 본질을 정확히 꿰뚫는 표현이라고 생각했다. PUT 요청이 실패했던 이유도 이제 명확했다. 솔라는 조립의 가장 중요한 부품인 ‘메서드’와 ‘바디’를 끼워 넣을 공간조차 없는 브라우저에 대고 억지를 부리고 있었던 셈이다.
“결국 POST나 PATCH, DELETE 요청을 테스트하려면, 그 요청들을 제대로 ‘조립’할 수 있는 이런 전문 도구가 반드시 필요했던 거구나. 브라우저로는 애초에 불가능했던 거고.”
이제 막연했던 의문이 풀리면서 눈앞의 도구가 전혀 다르게 보였다. 복잡하기만 했던 계기판이, 이제는 모든 것을 가능하게 해 줄 만능 도구처럼 느껴졌다.
솔라는 다시 자리에 앉아 키보드에 손을 올렸다.
“좋아, 그럼 이 조립 도구로 진짜 요청을 한번 만들어 보고 싶어. 아까 실패했던 GET 요청부터 다시 한번 보내보자. 이번엔 제대로 ‘조립’해서!”
3장: 첫 요청: Postman으로 GET API 실험하기
솔라의 손가락이 파란색 ‘Send’ 버튼 위를 맴돌았다. 루나의 노트북에서 봤던 그 복잡한 Postman 화면이 이제 솔라의 모니터에도 떠 있었다. 이전의 실패를 반복하지 않으려는 듯, 솔라는 화면의 구성 요소들을 차근차근 확인했다.
메서드 선택 상자는 GET으로 잘 설정되어 있었다. 그 옆의 주소창에는 방금 만든 API의 주소 http://localhost:8080/users를 입력했다. 여기까지는 브라우저 주소창과 크게 다를 바 없어 보였다. 이제 보내기만 하면 되는 걸까?
“음, 그냥 이렇게 보내면 모든 사용자 목록을 다 가져오겠지?”
솔라는 혼잣말을 하며 마우스를 움직였다. 하지만 API 명세서에는 특정 조건을 가진 사용자만 조회하는 기능도 있었다. 예를 들어, id가 1인 사용자만 가져오거나, 이름을 기준으로 정렬하는 기능. 브라우저에서라면 주소 뒤에 ?id=1 같은 걸 붙여서 해결했었다.
“Postman에서도 그냥 여기 주소창에 ?id=1이라고 직접 타이핑하면 되려나? GET 요청은 어차피 간단하니까, 브라우저랑 똑같지 않을까?”
솔라는 습관처럼 주소창 끝에 물음표를 입력하려던 순간, 루나가 화면의 다른 곳을 가리켰다. 주소창 바로 아래에 있는 Params라는 탭이었다.
“거기 한번 열어볼래?”
솔라는 잠시 망설이다가 Params 탭을 클릭했다. 그러자 주소창 아래로 새로운 입력 공간이 나타났다. KEY와 VALUE라는 제목이 붙은, 마치 표처럼 생긴 입력 칸들이었다.
“이건 또 뭐지? 파라미터(Parameter)를 입력하는 곳인가 본데… 그냥 주소에 쓰는 거랑 뭐가 다르지?”
솔라가 의아해하며 투덜거리자, 루나가 차분한 목소리로 말했다.
“KEY에 id라고 입력해 봐.”
솔라는 반신반의하며 첫 번째 KEY 입력 칸에 id를 타이핑했다. 그리고 VALUE 칸으로 커서를 옮겨 숫자 1을 입력했다.
바로 그 순간, 놀라운 일이 일어났다.
솔라가 VALUE 칸에 ‘1’을 입력하자마자, 위쪽의 주소창이 저절로 바뀌었다. 원래 http://localhost:8080/users였던 주소 뒤에 ?id=1이라는 문자열이 자동으로 착 달라붙었다.
“어!”
솔라의 눈이 커졌다. 그녀는 시험 삼아 Params 탭의 체크박스를 껐다 켰다 해봤다. 체크를 끄자 주소창에서 ?id=1이 사라졌고, 다시 켜자 마법처럼 나타났다.
“와… 대박. 내가 Params에 키랑 값을 입력하니까, Postman이 알아서 올바른 URL 형식으로 조립해 주는 거였네!”
솔라는 흥미가 동해 한 줄을 더 추가했다. KEY에는 sort, VALUE에는 name을 입력했다. 그러자 주소창은 http://localhost:8080/users?id=1&sort=name으로 실시간 변경되었다. 앰퍼샌드(&) 기호까지 정확한 위치에 자동으로 붙었다. 브라우저에서 직접 타이핑할 때 종종 헷갈렸던 부분이었다.
“알겠다! 브라우저에서는 그냥 한 줄짜리 긴 ‘주소’라고만 생각했는데, 사실은 ‘목적지 주소’ 부분이랑 ‘부가 조건(파라미터)’ 부분으로 나뉘어 있었던 거구나. Postman은 이 둘을 명확하게 분리해서 보여주고, 내가 각 부분에만 집중해서 입력하면 알아서 합쳐주는 거였어.”
이것이야말로 진정한 ‘요청 조립’이었다. 주소조차도 부품별로 관리할 수 있다는 사실이 솔라에게는 새로운 발견이었다.
이제 정말 요청을 보낼 준비가 끝났다고 생각했을 때, 루나가 한마디 덧붙였다.
“잠깐. 그 API, 테스트하려면 인증 토큰이 필요하지 않았어?”
“아, 맞다!”
솔라는 Params 탭 옆에 있는 Headers 탭을 눌렀다. 역시 KEY, VALUE 형식의 입력 칸들이 나타났다. 솔라는 익숙하게 KEY 칸에 Authorization을, VALUE 칸에 임시로 발급받은 Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... 토큰 값을 붙여넣었다.
이제야 비로소 하나의 GET 요청이 완벽하게 조립된 모습이 눈앞에 펼쳐졌다.
- 메서드:
GET - 주소:
http://localhost:8080/users - 파라미터:
id=1,sort=name(별도 관리) - 헤더:
Authorization토큰 (별도 관리)
솔라는 깊게 숨을 들이쉬고, 마침내 ‘Send’ 버튼을 힘주어 눌렀다.
잠시 후, 화면 아래쪽 응답(Response) 패널에 초록색 불이 들어왔다.
Status: 200 OK
그리고 그 아래 Body 창에는 id가 1인 사용자의 정보가 담긴 JSON 데이터가 깔끔하게 표시되었다.
“됐다! 성공이야.”
솔라는 안도의 한숨을 내쉬었다. 단순해 보였던 GET 요청조차도 Postman 안에서는 이렇게 명확한 부품들로 분해되고 조립되었다. 더 이상 길고 복잡한 URL을 보며 눈을 가늘게 뜰 필요가 없었다.
성공의 기쁨을 만끽하던 솔라의 시선이 문득 한 곳에 머물렀다. Params, Headers 탭 옆에 있는 Body 탭이었다. GET 요청에서는 회색으로 비활성화되어 있었다.
“GET 요청은 성공했어. 그런데 여기 Body 탭은 왜 막혀있지? 아까 내가 실패했던 PUT이나 새로 데이터를 만드는 POST 요청은 Body에 데이터를 담아서 보내야 한다고 했잖아. 그럼 데이터를 실어 보내야 하는 요청은 여기서 어떻게 조립하는 거지?”
4장: 데이터 전송: Postman으로 POST API 실험하기
솔라의 Postman 화면에서 초록색 GET 글자가 파란색 POST로 바뀌었다. 그 작은 변화 하나만으로 화면 전체의 분위기가 달라졌다. 이전에 GET을 선택했을 때는 회색으로 잠겨 있던 Body 탭이 이제는 활성화되어 솔라의 클릭을 기다리고 있었다. 마치 닫혀 있던 화물칸의 문이 열린 것 같았다.
GET 요청 실험에 성공한 솔라는 자신감을 얻어 새로운 사용자 데이터를 생성하는 POST API 테스트에 도전하기로 했다. API 명세서에는 생성할 사용자 정보를 JSON 형식으로 만들어 Body에 담아 보내라고 명시되어 있었다.
“GET 요청은 서버에 뭔가를 ‘달라고’ 하는 거라 짐칸(Body)이 필요 없었지만, POST는 ‘이것 좀 새로 만들어줘’ 하고 데이터를 직접 ‘갖다주는’ 거니까 짐칸이 필요한 거구나.”
솔라는 활성화된 Body 탭을 망설임 없이 클릭했다. 넓은 텍스트 입력창이 나타나자, 그녀는 미리 준비해 둔 새로운 사용자 데이터를 붙여넣었다.
{
"name": "Nova",
"email": "nova@example.com"
}
“좋았어. 이제 보낼 데이터도 실었고, 주소도 http://localhost:8080/users로 맞췄고. 메서드도 POST로 바꿨으니… 보내기만 하면 되겠지?”
솔라는 모든 준비가 끝났다고 생각했다. 어차피 Body는 그냥 텍스트를 넣는 공간일 뿐이라고, 간단하게 여겼다. 그녀의 손가락이 ‘Send’ 버튼으로 향하려는 순간, 옆에서 보고 있던 루나가 조용히 화면의 한 부분을 가리켰다. 솔라가 데이터를 붙여넣은 텍스트 영역 바로 위, 여러 개의 라디오 버튼이 나란히 놓여 있는 곳이었다.
● none ○ form-data ○ x-www-form-urlencoded ○ raw ○ binary
“저건 뭐지?”
솔라는 그제야 그 선택지들을 발견했다. raw라는 단어가 눈에 들어왔다. ‘가공하지 않은 데이터’라는 뜻인가? 호기심에 raw 버튼을 클릭했다. 그러자 오른쪽에 Text라고 쓰인 새로운 드롭다운 메뉴가 나타났다.
“어? 뭐가 또 생겼네.”
솔라가 Text 드롭다운을 누르자, 익숙한 단어들이 목록으로 펼쳐졌다.
Text
JavaScript
JSON
HTML
XML
그 목록에서 ‘JSON’이라는 단어를 발견한 순간, 솔라의 머릿속에 번개가 쳤다.
“아! 그냥 데이터를 툭 던져놓기만 하면 되는 게 아니었어! 내가 보내는 이 텍스트 덩어리가 어떤 ‘형식’의 데이터인지 서버에게 알려줘야 하는 거구나.”
그녀는 마치 올바른 서류 양식을 찾은 사람처럼 망설임 없이 JSON을 선택했다. 그러자 밋밋했던 텍스트 영역의 데이터가 순식간에 알록달록한 색깔 옷을 입었다. 키는 파란색으로, 값은 주황색으로 바뀌며 가독성이 훨씬 좋아졌다. Postman이 이 데이터가 JSON임을 ‘이해’했다는 명백한 증거였다.
“잠깐만. 내가 여기서 데이터 형식을 JSON으로 지정하면… 그럼 서버는 이걸 어떻게 알지?”
루나가 이번에는 Headers 탭을 가리켰다. 솔라는 Headers 탭으로 이동했다. 아까 GET 요청 때 직접 입력했던 Authorization 헤더 외에, 처음 보는 헤더가 목록에 자동으로 추가되어 있었다.
| KEY | VALUE |
|---|---|
| Authorization | Bearer eyJhbGci… |
| Content-Type | application/json |
| … | … |
“Content-Type? 내용물 종류?”
솔라는 자신이 한 행동과 그 결과를 연결 지어 보기 시작했다. Body 탭에서 데이터 형식을 JSON으로 선택했더니, Headers 탭에 Content-Type이 application/json으로 자동 설정되었다.
“알겠다! 이 Content-Type 헤더가 바로 서버에게 보내는 ‘안내문’이었구나! 소포 상자에 ‘내용물: 유리, 취급 주의’라고 써 붙이는 것처럼, 이 헤더가 ‘지금 보내는 Body 안의 데이터는 JSON 형식입니다’라고 친절하게 알려주는 역할을 하는 거였어.”
솔라는 비로소 데이터 전송의 마지막 퍼즐 조각을 맞춘 기분이었다. Body는 단순한 텍스트 창이 아니었다. 내용물을 담고, 그 내용물이 무엇인지 정확한 형식(Type)을 지정한 뒤, 그 정보가 담긴 안내문(Header)까지 붙여야 비로소 완성되는 정교한 ‘화물칸’이었다.
이제 모든 것이 명확해졌다.
- 메서드:
POST - 주소:
http://localhost:8080/users - 바디:
raw데이터 형식,JSON타입으로 지정된 사용자 정보 - 헤더: 자동으로 추가된
Content-Type: application/json
솔라는 다시 한번 확신을 갖고 ‘Send’ 버튼을 눌렀다.
곧이어 응답 패널에 새로운 상태 코드가 떴다.
Status: 201 Created
‘200 OK’가 아닌 ‘201 Created’. 서버가 요청을 성공적으로 처리했을 뿐만 아니라, 새로운 무언가를 ‘생성’했음을 알려주는 명백한 신호였다. 응답 Body에는 서버가 방금 생성한, id 값이 새로 부여된 Nova의 정보가 담겨 있었다.
“성공이다! 이제 데이터를 보내는 방법도 확실히 알겠어.”
솔라는 뿌듯함을 느끼며 Postman의 메서드 선택창을 다시 바라보았다. GET과 POST는 이제 그녀에게 정복된 영역이었다. 하지만 그 아래 PUT, PATCH, DELETE가 여전히 남아 있었다.
“POST로 새 데이터를 만들었으니까, PUT이나 PATCH로는 데이터를 수정할 수 있겠지? 그럼 걔네도 Body가 필요하겠네. 그런데 DELETE는? 데이터를 지우는데도 Body가 필요한가? 아니면 GET처럼 Body 없이 보내나? 이젠 나머지 요청들도 전부 제대로 실험해보고 싶어.”
5장: 다양한 메서드: PATCH, DELETE로 API 실험 완성하기
솔라의 Postman 화면에는 방금 성공한 POST 요청의 흔적이 선명하게 남아있었다. 응답 패널에는 Status: 201 Created라는 초록색 글씨와 함께, 새로 생성된 사용자 ‘Nova’의 정보가 JSON 형식으로 표시되어 있었다. 성공의 기쁨도 잠시, 솔라의 시선은 다시 화면 상단의 메서드 선택창으로 향했다.
그녀는 파란색 POST 버튼을 클릭했다. 익숙해진 GET과 POST 아래로, 아직 미답의 영역인 PUT, PATCH, DELETE가 차례로 보였다. ‘새로운 데이터를 만들었으니, 이제 수정하고 삭제할 차례지.’ 솔라는 마음속으로 중얼거리며 다음 실험 대상을 정했다. 방금 만든 ‘Nova’의 이메일 주소를 수정해보기로 했다.
“좋아, 부분 수정은 PATCH를 쓰라고 했으니까… 이걸로 해보자.”
솔라는 메서드 목록에서 PATCH를 선택했다. 메서드 이름이 보라색으로 바뀌었을 뿐, 화면의 다른 부분은 POST 때와 거의 똑같았다. Body 탭도 여전히 활성화되어 있었다.
“POST랑 비슷하겠네. 수정할 데이터를 Body에 넣어서 보내면 되겠지?”
솔라는 POST 요청의 응답으로 받았던 Nova의 전체 JSON 데이터를 복사했다. 그리고 PATCH 요청의 Body 탭으로 돌아와 붙여넣기 한 뒤, email 값만 nova@new-example.com으로 수정했다. 전체 데이터를 보내서 그중 일부만 바꾸는 방식이 가장 안전하다고 생각했다. 수정할 대상의 id를 URL 끝에 붙이는 것도 잊지 않았다.
URL: http://localhost:8080/users/2 (Nova의 id가 2라고 가정)
Body:
{
"id": 2,
"name": "Nova",
"email": "nova@new-example.com"
}
모든 준비가 끝났다고 생각한 솔라는 ‘Send’ 버튼을 눌렀다. 잠시 후, Status: 200 OK라는 응답이 돌아왔다. 성공이었다.
“됐네! 역시 POST랑 거의 똑같잖아.”
솔라가 만족스러워하는 순간, 옆에서 지켜보던 루나가 화면을 가리키며 말했다.
“그럼 이번엔, Body에 이메일 주소만 남기고 보내볼래?”
“응? 이메일만? 그래도 될까? 이름(name) 같은 다른 정보가 다 날아가는 거 아니야?”
솔라는 의아해했지만, 루나의 말대로 Body의 내용을 모두 지우고 딱 한 줄만 남겼다.
Body:
{
"email": "nova@very-new-example.com"
}
‘설마 이렇게 보낸다고 서버가 알아서 이메일만 바꿔줄까?’ 솔라는 반신반의하며 다시 ‘Send’ 버튼을 눌렀다. 결과는 놀라웠다. 또다시 Status: 200 OK 응답이 돌아왔고, 응답 Body에는 이메일만 새로 업데이트된 Nova의 전체 정보가 표시되었다. 기존의 name 값은 그대로 유지되어 있었다.
“아…!”
솔라는 두 번의 실험 결과를 비교하며 무릎을 쳤다.
“PATCH는 정말 ‘수정 패치’ 같은 거구나! 내가 보낸 정보만 콕 집어서 기존 데이터에 덧붙여주는 거였어. POST처럼 전체 데이터를 보내는 게 아니라, 바꿀 부분만 보내는 게 핵심이었네. Postman의 사용법은 비슷해 보여도, 각 메서드의 진짜 의미를 알아야 제대로 활용할 수 있는 거였어.”
이제 마지막 관문이 남았다. DELETE. 솔라는 메서드 선택창에서 망설임 없이 DELETE를 골랐다. 메서드 이름이 빨간색으로 바뀌는 순간, 묘한 긴장감이 흘렀다.
“DELETE는… 데이터를 지우는 거니까, 보낼 데이터는 없겠지?”
솔라는 스스로에게 질문을 던지며 Body 탭을 확인했다. none으로 깨끗하게 비워져 있었다. 그녀는 이제 확신을 갖고 있었다. 삭제할 대상을 특정하는 것은 URL의 역할일 뿐, Body에 무언가를 실어 보낼 이유가 없었다. 솔라는 방금 수정했던 Nova의 id가 포함된 URL(http://localhost:8080/users/2)을 그대로 둔 채 ‘Send’ 버튼을 눌렀다.
결과는 즉시 돌아왔다. 하지만 이번에는 익숙한 200 OK나 201 Created가 아니었다.
Status: 204 No Content
그리고 응답 Body 영역은 텅 비어 있었다. 아무런 데이터도 없었다.
“204? ‘내용 없음’?”
솔라는 잠시 멈칫했지만, 이내 그 의미를 깨달았다. “서버가 ‘요청하신 대로 사용자를 성공적으로 삭제했고, 그래서 돌려줄 내용이 없습니다’라고 말해주는 거구나.”
GET, POST, PATCH, DELETE. 마침내 모든 주요 요청을 자신의 손으로 직접 ‘조립’하고 ‘실험’해 본 순간이었다. 솔라는 Postman 창을 천천히 훑어보았다. 더 이상 복잡한 계기판이 아니었다. 어떤 API 명세서를 가져와도 완벽하게 분해하고 테스트할 수 있는, 신뢰도 높은 만능 실험대였다.
그녀는 문득 이 모든 여정의 시작이었던, 브라우저 주소창에 PUT을 입력했다가 실패했던 순간을 떠올렸다. 이제는 그 PUT 요청도 제대로 보낼 수 있을 것 같았다.
솔라는 마지막으로 메서드를 PUT으로 바꾸고, 첫 번째 사용자의 id인 1을 URL에 입력했다. PUT은 전체를 교체하는 메서드이므로, Body에 id를 제외한 사용자의 모든 정보를 JSON 형식으로 꼼꼼하게 채워 넣었다.
- 메서드:
PUT(교체) - 주소:
http://localhost:8080/users/1 - 바디: 교체할 전체 사용자 정보
- 헤더:
Content-Type: application/json
떨리는 마음으로 ‘Send’ 버튼을 누르자, 화면에 Status: 200 OK가 선명하게 떴다. 모든 것이 완벽했다. 브라우저 앞에서 막막했던 자신은 더 이상 없었다. 이제 솔라는 어떤 API를 마주하든, 요청의 각 요소를 분리해 생각하고, Postman이라는 실험대 위에서 차분히 조립하여 그 결과를 자신의 눈으로 확인할 수 있는 개발자가 되어 있었다.