[intellij] http client 로 api 테스트 대체하기

jomminii·2024년 4월 9일

intellij

목록 보기
2/2
post-thumbnail

이번에는 인텔리제이가 제공하는 api 테스트 플러그인인 http client를 사용해보겠습니다.

기존에는 IDE 를 Visual Studio Code 를 사용하면서 http yac 플러그인으로 http 테스트를 했었는데요. 이번에 IntelliJ Ultimate 버전을 쓸 수 있게 되면서 내부 플러그인인 http client 를 통해 테스트 하는 방식으로 바꾸게 되었습니다. (커뮤니티 버전은 http client 를 사용할 수 없어요)


⛱️ 기본 사용법

  1. 디렉토리 설정
  • http 파일들을 관리할 디렉토리를 따로 설정 합니다. 저 같은 경우는 기존의 http yac 과 구분하기 위해서 최상위 디렉토리/https-intellij/로 설정했습니다.
  1. env 변수를 설정 합니다.
  • http 파일들 전체에서 공용으로 사용할 환경변수들을 설정합니다. host 정보 등이 들어갈 수 있습니다. 세부 설정은 아래 env 변수 파트에서 추가로 확인해보세요!
  1. .http 파일 작성
  • .http.rest 로 끝나는 파일을 작성합니다.
  1. 실행 환경을 설정합니다.
  • 파일별로 실행 환경을 미리 설정할 수 있고, 실행 때마다 환경을 선택하게 할 수도 있습니다.
  1. 파일 내 시작 버튼으로 테스트를 실행합니다.

🎡 좀 더 사용법

a. env 변수

  • 공통 환경변수를 관리하기 위해서는 http-client.env.json 이라는 파일이 필요합니다. http 파일을 관리하는 디렉토리 내에 위치시키면 되고, 직접 파일을 만들거나 http 파일 상단의 기능을 통해 추가할 수 있습니다.

public 과 private 으로 파일을 나눌 수 있고, private 의 경우 http-client.private.env.json 이라는 파일로 생성이 됩니다.

IDE 상에서 gitignore 를 시켜준다고는 하는데 그것보다는 .gitignore 내에 명시적으로 푸시를 막는게 좋아보이긴 해요!

전 public, private 파일 외에 _http-client.private.env.json 이라는 파일을 추가로 작성하고, private 을 위한 틀을 담아뒀어요. 다른 사람들도 이 형식으로 private 파일을 작성해둬야 기능을 쓸 수 있거든요. 이렇게 틀을 만들고, README에 파일명을 바꾸고 내부 정보를 바꿔서 사용하라고 안내했어요.

{
    "dev": {
        "loginId": "testId1",
        "loginPassword": "password1"
    },
    "prod": {
        "loginId": "testId2",
        "loginPassword": "password2"
    }
}

private 과 public 둘다 작성 양식은 똑같고, 위처럼 각 환경(dev, prod 등)마다 각 변수를 어떻게 쓸 지 정의하면 돼요.

만약 둘 다 같은 변수가 정의되어 있다면, 최종적으로 private 의 값이 사용되게 되니 참고하세요!

http 파일 내에서는 {{변수명}} 으로 값을 가져다 쓸 수 있어요.

### 로그인
# @name: login
POST {{host}}/login
Content-Type: {{requestContentTypeJson}}

{
    "id": "{{loginId}}",
    "password": "{{loginPassword}}"
}

참고로 http 파일 내에 지역 변수를 선언할 수도 있는데요, 만약 env 와 같은 변수가 아래처럼 정의될 경우에는 지역 변수가 최종 적용됩니다.

#@loginId = testId3

b. 지역 변수

지역 변수는 특정 http 파일 내에만 적용되는 변수를 의미합니다.
@변수명 = 값 형식으로 선언할 수 있고, env 변수로 선언한 값과 동일한 변수가 있다면, 지역 변수로 덮어씁니다.

한 가지 유의할 점은 지역 변수끼리는 override 가 되지 않아서, 동일한 변수를 같은 이름으로 같은 파일 내에서 사용할 수가 없더라고요. 이게 좀 불편했어요. http yac 에서는 override가 되서 동일한 변수명을 다른 API 에서도 사용할 수 있었는데, 여기서는 안되서 무조건 다른 변수명으로 바꿔줘야 했어요.


@loginId = testId3
@loginPassword = testPassword3

### 로그인
POST {{host}}/login
Content-Type: {{requestContentTypeJson}}

{
    "id": "{{loginId}}",
    "password": "{{loginPassword}}"
}

# 다른 변수명 사용
[X] @loginId = testId4
[O] @loginId1 = testId4

### 어떤 다른 API
POST {{host}}/login/test
Content-Type: {{requestContentTypeJson}}

{
    "id": "{{loginId}}",
    "password": "{{loginPassword}}"
}



c. 글로벌 변수

어떻게 보면 env 변수도 글로벌 변수라고 볼 수 있을 것 같은데, 여기서 말하는건 env 변수 는 아니고요. 전체 http 파일에서 적용되는 글로벌 변수를 선언하고 사용할 수 있어요.

http 파일 내에서 > {% javascript 코드 %} 형식으로 자바스크립트 코드를 사용할 수 있는데요. 요청 후의 response 를 읽어서 그 값을 활용한 후 처리를 할 수 있습니다.

일반적으로 로그인 인증을 위한 토큰을 사용하고 싶을 때 글로벌 변수를 활용할 수 있는데요. 다른 API 를 호출하기 전에 로그인 API 를 먼저 실행시키고, 리턴 받은 토큰을 글로벌 변수에 저장합니다.

### 로그인 - 2차인증
# @name login_2fa
POST {{host}}/login/2fa
Content-Type: {{requestContentTypeJson}}

{
    "id": "{{loginId}}",
	...
}

> {%
    if (response.body && response.body.accessToken) {
        client.global.set("accessToken", response.body.accessToken)
    } else {
        client.global.set("accessToken", "")
    }

%}

그리고 나서 다른 API 에서 아래처럼 다른 변수들처럼 불러와 사용할 수 있어요. 참고로 다른 파일에서도 아래처럼 변수를 불러와 사용할 수 있는데요, 인텔리제이가 현재 파일 내에 변수를 선언하지 않았다고 밑줄을 그어버립니다.

### 조회 API
@pk_no=1
GET {{host}}/asset/{{pk_no}}
Authorization: bearer {{accessToken}}

그래서 전 밑줄이 보기 싫어서 env 변수에 동일한 글로벌 변수를 디폴트로 선언해놔서 밑줄을 제거 했어요. 이런 방법도 있다는거 참고해보세요!

{
    "dev": {
      	...,
        "accessToken": "디폴트세팅용"
    }
}

d. 요청 전 다른 API 요청 처리

아마 대부분의 API 호출에는 인증 로직이 들어갈텐데요, 호출 전에 로그인 로직을 한 번은 실행해야 토큰이 글로벌 변수에 저장되기 때문에 매번 이 과정을 거쳐줘야 합니다. 토큰 유효시간 내에는 유효하긴 하지만, 그 사이에 로직이 변할 수도 있고, 등등의 사유로 매번 로그인을 새로 해주는게 좋긴 한데요.

http yac 에서는 @forceref 기능으로 매 request 마다 강제로 실행할 로직을 선언할 수 있는 걸 제공해서 편했는데, 인텔리제이는 코드상의 기능은 제공하지 않더라고요.

# http yac

# @forceRef login
# @forceRef login_2fa
@pk_no=1
GET {{host}}/asset/{{pk_no}}
Authorization: bearer {{accessToken}}

다행히 방법은 있었어요.

Run/Debug Configuration 을 활용하는 방법인데요. 일단 login 에 필요한 1차 인증, 2차 인증 request 를 login.http 라는 파일에 모읍니다.

그 후 전체 실행을 통해 로그인 로직을 한 번 실행합니다. 그러면 인텔리제이 맨 오른쪽 최상단에 login.http 의 모든 것을 실행했다는 All in login 이 노출됩니다.

그 이후 edit > Edit configuration templates 로 진입합니다.


여기서는 HTTP Request 에 공통으로 적용시켜줄 템플릿을 정할 수 있는데요. Run Another Configuration 을 각 요청 실행(launch) 전에 실행할 수 있도록 설정하려고 합니다.

버튼을 누르고 나면, 실행할 수 있는 항목 리스트가 노출되는데요, 우린 방금 로그인 로직을 실행했어서 해당 configuration 이 노출되고 있습니다.

All in login 을 클릭하면 설정이 완료되고요.

그리고 나서 다른 request 를 실행하면 로그인 로직이 실행된 후 요청한 request 가 실행되는 걸 볼 수 있습니다.

전체 적용이 싫다면, 개별적으로 Before launch 부분에 원하는 사전 설정을 넣어주면 됩니다.

e. name 지정

아래처럼 # @name login 코드를 작성하면, login 이라는 이름으로 request 가 지정됩니다. 지정하지 않으면 로그인 으로 지정됩니다.

### 로그인
# @name login

요런식으로 결과를 노출할 때 파일명 | name으로 노출해 줄 때 사용됩니다. configuration 에서 리스트 출력할 때도 사용되고요.


💾 http yac 과의 차이점 몇개

http client 기준으로 얘기해볼게요.

  1. body 부분의 주석까지 포함하여 request 를 날려버림
  • 아래처럼 바디 밑에 주석을 달아놓으면 이거까지 날려버려서 에러를 내버립니다. yac 에서는 안그래서 테스트 케이스를 주석으로 좀 달아놨었는데, 쓸 수 없게 됐어요.
...
POST {{host}}/login/2fa
Content-Type: {{requestContentTypeJson}}

{
    "id": "{{loginId}}",
	...
}
  
//abcdef
  1. 지역 변수 overriding 안됨. 무조건 다른 변수로 지정 필요.
  2. env 변수 지정 파일 및 형식 다름
# yac
request_rejectUnauthorized=false

# http client
{
    "dev": {
        "request_rejectUnauthorized": false
    }
}
  1. api path 앞에 {{host}} 를 지정해줘야함
# yac - host 명시 안해도 env 에서 읽어서 앞에 넣어줌
POST /login/2fa


# http client
POST {{host}}/login/2fa
  1. global 변수 선언 방식
# yac -- js 없이 아래와 같이 선언
{{
    $global.loginId = 'testId1'
    $global.loginPassword = 'testPassword1'
}}

# http client - js로 선언
> {% client.global.set("accessToken", response.body.accessToken) %}
  1. 코드 내 사전 request 호출 선언 불가
# yac - 사전 request 지정해서 호출 가능

# @forceRef login
# @forceRef login_2fa
POST {{host}}/login/2fa

# http client
Run/Debug Configuration 으로 설정

그 외 생략

📱 결론

인텔리제이 ultimate 을 사용한다면 postman 대용으로 사용하기 좋습니다. js 코드를 통해 assert 등의 키워드로 테스트도 일부 가능하다고 하나, http client 를 이용하기보다는 테스트 코드를 따로 작성하는게 케이스 관리나 더 다양한 테스트가 용이해 보입니다.


📞 참고

profile
고민은 격렬하게, 행동은 단순하게

0개의 댓글