본문 바로가기
IDE/PostMan

PostMan Hoeny Tips 3

by 코딩하는보기 2023. 9. 25.
320x100

아주 오랜만에 포스트맨 관련 팁을 쓰는 것 같다..!!

 

PostMan의 여~~~러 가지 사용 방법에서

ResponseBody를 포스트맨의 환경 변수로 저장하는 포스팅을 했었다

 

좀 더 고도화해서 팁을 추가해보려고 한다

목차

1.  post-man HTTP /POST 요청 시에 body값 주석
2.  response응답에서 headers, body를 뽑아서 환경변수로 저장
3. 단일 request가 아닌, collection 요청 헤더에 전역으로 추가

-------------------------------------------------------------------------------------

1.  post-man HTTP /POST 요청 시에 body값 주석

일단은 postman 테스트를 하기 위한 backend 로직을 간단하게 만들어본다

개발 언어는 kotlin, 프레임워크는 spring boot 3.1.3 을사용했다

문법사용 목록

- 변수 if return

- named parameter

- elvis operator

- triple-quote String

 

- 1. /Post auth

  심플하게 email, password를 받아서, 요청한 값을 response에 보내주고(null인 경우 null 표시), 

  email, password 둘 다 값이 있을 경우만 accessToken을 response 헤더 및 바디로 내려준다(token은 jwt.io 기본값 참고)

- 2. /Get test

  Acess-Token이라는 헤더에 값이 있을 때만 응답 OK, 그렇지 않은 경우는 RunTimeException을 내보내도록 했다

package com.boki.spring-boki.controller

import org.springframework.http.HttpHeaders
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RestController

@RestController
class HomeController {

    @PostMapping("/auth")
    fun auth(
    	@RequestBody authReq: AuthReq?
    ): ResponseEntity<Any> {
        val authRes = AuthRes(
                email = authReq?.email,
                password = authReq?.password,
        )
        println("https://code-boki.tistory.com/")
        val mockJWT = if (authReq?.email != null && authReq.password != null) {
            """
            eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
            eyJzdWIiOiIxMjM0NTY3ODkwIiwibnFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
            SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
        """.trimIndent().replace("\n", "")
        } else {
            null
        }
        authRes.accessToken = mockJWT

        val headers = HttpHeaders()
        mockJWT?.let {
            headers.add("accessToken", it)
        }
        println("https://code-boki.tistory.com/")

        return ResponseEntity.ok().headers(headers).body(authRes)
    }

	@GetMapping("/test")
    fun test(@RequestHeader(value = "Access-Token") accessToken: String?): String {
        println("https://code-boki.tistory.com/")
        return accessToken?.let { "OK" }
                ?: throw RuntimeException("Access token is missing!")
    }
}

data class AuthReq(
        val email: String?,
        val password: String?,
)

data class AuthRes(
        val email: String?,
        val password: String?,
        var accessToken: String? = null,
)

- 구현 테스트(테스트코드 대신 postman으로 대체)

만약 password가 없다면?

근데 저렇게 password를 지워버리고 요청을 보내고 저장하면.. 이전 값이 뭐였는지 기억이 안날 것이다

그럴때 주석을 달 수 있다. json의 키앞에 #을 붙여주면 된다

email value 뒤에 ,를 없애줄 필요도 없다

{
    "email": "test@test.com",
    "#password": 12345678
}

이런식으로 말이다

다시 요청해본다

성공이다. 앞으로의 Post 요청에 대한 json data의 주석은 #으로 해주면 된다. 


2.  response응답에서 headers, body를 뽑아서 환경변수로 저장

자, 그러면 이제 응답을 한번 찍어보자..!

postman의 tests탭에 아래의 코드를 추가하고, 하단의 Console 탭을 열어서 Clear를 해주자

// 응답 headers, body
var headerResponse = responseHeaders
var bodyResponse = JSON.parse(responseBody)

console.log('headers', headerResponse)
console.log('body', bodyResponse)

그리고 요청을 보내고 아래를 확인하면!

콘솔 창을 확인 할 수 있다

기본적으로 responseBody는 string으로 오기 때문에, server의 response가 json형태라면, parsing을 한번 거쳐서 객체로 만들어줘야 한다

그럼 이제 기본 셋팅은 끝났다

서버에서 응답 헤더와 바디에 둘다 accessToken을 내려 주었으니, 클라이언트에서도 받아서 postman 환경 변수에 저장해보자

아래의 코드를 Tests에 추가한다

// 응답 headers, body
var headerResponse = responseHeaders
var bodyResponse = JSON.parse(responseBody)

// 필요한 정보 뽑기
var accessTokenHeader = headerResponse['accessToken']
var acessTokenBody = bodyResponse.accessToken

// header로 token이 넘어오는 경우
if (accessTokenHeader != null) pm.environment.set('acessTokenHeader', accessTokenHeader)
else pm.environment.set('acessTokenHeader', null)

// body token이 넘어오는 경우
if (acessTokenBody != null) pm.environment.set('acessTokenBody', acessTokenBody)
else pm.environment.set('acessTokenBody', null)

다시 api Call을 요청하고 Environment 탭으로 넘어가서 확인해본다

기본적으로 apiUrl같은 변수들이 생성되어 있다고 가정했다

응답헤더와 바디 환경 변수에 값이 잘 저장되어 있는 것을 확인했다

회사 또는 개인 프로젝트의 환경에서 header로 토큰을 내려줄지, body로 토큰을 내려줄지 스펙을 정해서 처리하면 될것이다!


3. 단일 request가 아닌, collection 요청 헤더에 전역으로 추가

이번에는 POST /auth 가 아닌 GET /test를 테스트 할 것이다

위의 로직 설명대로

- 2. /Get test

  Acess-Token이라는 헤더에 값이 있을 때만 응답 OK, 그렇지 않은 경우는 RunTimeException을 내보내도록 했다

 

이전 포스팅이 기억 안나시는 분들을 위해 다시 포스트맨 설명을 하겠다!

서버에서 Access-Token 이라는 Key name으로 토큰값을 받도록 스펙을 요구하니, 우리도 그에 맞춰서 포스트맨 헤더에 아까 /auth 요청으로 받은 token값을 복사해서 넣어준다

OK가 떨어지는 것을 확인 했다

만약에 Access-Token이 없다면?

응답 본문 message에 RuntimeException의 cause message가 나와있는 것을 볼 수 있다

아직 응답메시지 처리를 안해서 에러 trace가 나와서 지저분하다. 하지만 이 포스팅에서는 얘기하지 않겠다

 

그럼 이제 조금 더 고도화를 해보자

계속 응답에서 토큰을 복사하고 붙여넣기로 해줄 순 없지 않는가?

아까의 환경변수를 이용해보자

헤더의 value를 {{}} 고래수염 brace를 이용해서 변수명으로 바꿔주고 테스트해보자

성공

 

그러면 여기서 문제점이 있고, 문제 해결을 해서 고도화를 할 수 있다

저 테스트 Collection에서 다수의 api 요청이 있고, 그 요청 하나하나마다 Access-Token 헤더에 Value를 셋팅해줘야 하는가?

문제상황을 만들어본다

서버에서 GET /test, /test1, /test2, /test3 이라는 API 요청 전체에 다 Header에서 토큰을 받아야 하는 상황이다
보통 이런 헤더작업은, Controller보다는 Filter(Security Filter)혹은 Interceptor, AOP에서 처리를 하는게 표준이다

    @GetMapping("/test")
    fun test(@RequestHeader(value = "Access-Token") accessToken: String?): String {
        println("https://code-boki.tistory.com/")
        return accessToken?.let { "OK" }
                ?: throw RuntimeException("Access token is missing!")
    }

    @GetMapping("/test1")
    fun test1(@RequestHeader(value = "Access-Token") accessToken: String?): String {
        println("https://code-boki.tistory.com/")
        return accessToken?.let { "OK" }
                ?: throw RuntimeException("Access token is missing!")
    }

    @GetMapping("/test2")
    fun test2(@RequestHeader(value = "Access-Token") accessToken: String?): String {
        println("https://code-boki.tistory.com/")
        return accessToken?.let { "OK" }
                ?: throw RuntimeException("Access token is missing!")
    }

    @GetMapping("/test3")
    fun test3(@RequestHeader(value = "Access-Token") accessToken: String?): String {
        println("https://code-boki.tistory.com/")
        return accessToken?.let { "OK" }
                ?: throw RuntimeException("Access token is missing!")
    }

 

이제 포스트맨에서 어떻게 API Test를 할 것인가가 남아있다

기존의 API를 copy(Cmd+D)해서 작업한다면 오류는 안나겠지만... 이런 단순노동 옳지않다고 본다!

테스트라는 Collection(API 요청 집합)에서는 헤더에 Access-Token을 자동으로 넣어주고 싶다

이런 요구사항의 경우 `테스트`의 Collection에 환경설정을 해 주면 된다

`테스트` Collection을 클릭하고 Pre-reqeust Script를 눌러준다

여기에 아래의 코드를 추가해준다

var acessTokenHeader = pm.environment.get('acessTokenHeader')
var accessTokenBody = pm.environment.get('acessTokenBody')

// Authorization + Bearer JWT 인증의 경우
// if (accessTokenBody != null) {
//     pm.request.headers.add({
//         key: "Authorization",
//         value: "Bearer " + accessTokenBody
//     })
// }

// 단순 custom 헤더 추가의 경우
if (accessTokenBody != null) {
    pm.request.headers.add({
        key: "Access-Token",
        value: accessTokenBody
    })
}

이제 GET /test, /test1, /test2, /test3에서 Header에서 값을 빼고도 응답이 통과가 되는지 테스트해본다

Access-Token을 uncheck하고 Send를 눌러도 OK가 떨어진다

성공!!

포스트맨을 좀 더 유용하게 사용하기 위한 포스팅을 마치겠다.

이 포스팅이 유용했다면 다른 글들도 읽어주시고,, 심심하면 광고도 눌러주고.. Contact이 필요하면 이메일로 궁금한것도 물어봐주면 답해주겠다

 

감사합니다!!!(는 왜 이것만 존댓말이냐..)

728x90

'IDE > PostMan' 카테고리의 다른 글

PostMan Honey Tips 2  (0) 2022.05.22
PostMan의 여~~~~러 가지 사용방법  (0) 2022.03.15

댓글