본문 바로가기
Java & Kotlin/Spring

[Spring] Swagger UI 대신 Scalar API Reference를 사용하여 API 문서 사용하기

by devson 2024. 10. 29.

Scalar API Reference는 Swagger UI를 대체할 수 있는 또다른 API 문서화 방법이다.

 

Swagger UI와 비교하였을 때 화면 구성이 깔끔하기도 하며 API를 호출할 때 Postman과 같은 편리한 UI를 제공해줘서 개인적으로는 Swagger UI의 대체제로써 훌륭한 선택이라는 생각이다.

 

이번 포스팅에서는 Spring Web MVC 프로젝트에서 Scalar API Reference를 사용하는 방법에 대해 알아보도록 하겠다.

 

(코드 예제는 여기에서 확인할 수 있다)

 


 

0. Scalar Quickstart 살펴보기

먼저 어떻게 Scalar API Reference를 사용하면 좋을지를 알아보기 위해

Scalar repository README에 있는 Quckstart를 살펴보자.

<!doctype html>
<html>
  <head>
    <title>Scalar API Reference</title>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <!-- Need a Custom Header? Check out this example https://codepen.io/scalarorg/pen/VwOXqam -->
    <script
      id="api-reference"
      data-url="https://cdn.jsdelivr.net/npm/@scalar/galaxy/dist/latest.json"></script>
    <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
  </body>
</html>

 

 

README에 위와 같은 짧은 html 코드가 있는데 이를 웹 브라우저에서 실행해보면 아래와 같은 API 문서가 나온다.

 

어떻게 이러한 문서가 나오게 되는걸까?

HTML의 14번째 줄을 보면 data-url에 json 파일을 사용하고 있는 걸 볼 수 있는데 이는 OpenAPI spec이다.

<!doctype html>
<html>
  <head>
    <title>Scalar API Reference</title>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <!-- Need a Custom Header? Check out this example https://codepen.io/scalarorg/pen/VwOXqam -->
    <script
      id="api-reference"
      data-url="https://cdn.jsdelivr.net/npm/@scalar/galaxy/dist/latest.json"></script>
    <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
  </body>
</html>

 

 

즉, OpenAPI spec 경로를 사용하여 15번째 라인의 스크립트를 통해 API 문서가 생성되는 것이다.

Scalar API Reference 위해서는 API의 OpenAPI spec를 가져올 수 있으면 된다.

 

이제 어떻게 Scalar API Reference를 사용할 수 있는지를 알아보았으니 Spring Web MVC프로젝트에서 Scalar API Reference를 어떻게 셋업할지 대해 살펴보자.

 

1. springdoc-openapi를 통해 OpenAPI spec 생성하기

Spring에서 OpenAPI spec을 만들고 Swagger UI를 실행하는 라이브러리로 가장 많이 사용되는 것이 springdoc-openapi 이다.

springdoc-openapi를 사용하기 위해 의존성을 추가해준다.

// build.gradle.kts
dependencies {
    implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0")
}

 

springdoc-openapi starter의 경우 기본적으로 /v3/api-docs를 통해 OpenAPI spec을 생성하게 된다.

서버를 실행한 뒤, /v3/api-docs 경로로 접속해보자.

 

이렇게 OpenAPI spec을 만드는 설정은 application.yml에서 켜고 끌 수 있다.

Scalar API Reference를 사용하기 위해서는 이 spec이 필요하기 때문에 이 설정은 기본값인 true로 두어야한다.

springdoc:
  api-docs:
    enabled: true # <===

 

2. API (Controller) 추가

API의 OpenAPI spec을 생성하는 설정을 마쳤기 때문에 예제를 위해 Controller를 생성하여 API를 추가해보자.

여기에서 API의 produces 옵션을 설정해줘야지 Scalar API Reference 상에서 응답 예제가 나오므로 더 명확한 문서를 위해 produces 옵션을 추가해주는 것을 추천한다..

 

// com.tistory.devs0n.scalar.UserController.kt
package com.tistory.devs0n.scalar

import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.*

@Tag(name = "User API")
@RestController
@RequestMapping("/api/users")
class UserController {
    private val users = mutableListOf(
        User(name = "Kim", country = "Korea", city = "Seoul"),
        User(name = "James", country = "USA", city = "New York"),
        User(name = "Chris", country = "Korea", city = "Incheon"),
    )

    @Operation(description = "사용자 조회")
    @GetMapping(produces = [MediaType.APPLICATION_JSON_VALUE]) // `produces` 설정을 해야 응답 예제가 나옴
    fun getUsers(
        @RequestParam(required = false) country: String?,
        @RequestParam(required = false) name: String?,
    ): List<User> {
        var response: List<User> = this.users

        if (country != null) {
            response = response.filter { it.country == country }
        }

        if (name != null) {
            response = response.filter { it.name == name }
        }

        return response
    }

    @Operation(description = "사용자 추가")
    @PostMapping(produces = [MediaType.APPLICATION_JSON_VALUE])
    fun addUser(@RequestBody request: User): User {
        this.users.add(request)
        return request
    }
}

@Schema(description = "사용자 정보")
data class User(
    @Schema(description = "이름", example = "Lee")
    val name: String,
    @Schema(description = "국가", example = "Korea")
    val country: String,
    @Schema(description = "도시", example = "Seoul")
    val city: String,
)

 

// com.tistory.devs0n.scalar.ProductController
package com.tistory.devs0n.scalar

import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.*

@Tag(name = "Product API")
@RestController
@RequestMapping("/api/products")
class ProductController {
    private val products = mutableListOf(
        Product(name = "Jeans", price = 55_000),
        Product(name = "T-shirt", price = 24_500),
    )

    @Operation(description = "제품 조회")
    @GetMapping(produces = [MediaType.APPLICATION_JSON_VALUE]) // `produces` 설정을 해야 응답 예제가 나옴
    fun getProducts(): List<Product> {
        return this.products
    }

    @Operation(description = "제품 추가")
    @PostMapping(produces = [MediaType.APPLICATION_JSON_VALUE])
    fun addProduct(@RequestBody request: Product): Product {
        this.products.add(request)
        return request
    }
}

@Schema(description = "제품 정보")
data class Product(
    @Schema(description = "제품명", example = "Jeans")
    val name: String,
    @Schema(description = "가격", example = "55_000")
    val price: Int,
)

 

그리고 다시 /v3/api-docs 경로를 확인해보면 OpenAPI spec에 새로 추가한 API에 대한 정보가 추가된 것을 확인할 수 있다.

 

3. Scalar API Reference 사용을 위한 html 추가

API의 OpenAPI spec을 가져올 수 있기 때문에 이를 사용하기만 하면 된다.

앞서 살펴본 html 파일에서 data-url 옵션만 /v3/api-docs로 변경해준 html 파일을 resources 디렉토리에 추가해준다.

<!doctype html>
<html>
<head>
    <title>Scalar API Reference</title>
    <meta charset="utf-8" />
    <meta
            name="viewport"
            content="width=device-width, initial-scale=1" />
</head>
<body>
<script id="api-reference" data-url="/v3/api-docs"></script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
</body>
</html>

 

(나의 경우 resources/static/api-spec/index.html 에 두었다)

 

이제 서버를 실행한 뒤에 저장한 html 파일 경로에 맞는 url에 접속해서 문서를 확인해보자.

(나의 경우 /api-spec/index.html)

 

API 문서가 잘 생성되었음을 확인할 수 있고 API를 호출하는 것 또한 잘 동작하는 것을 볼 수 있다.

 

4. Authorization 추가

JWT와 같이 요청 header에 인증 정보를 추가해야하는 경우가 있다.

Authorization 설정을 추가해보고 Scalar API Reference에서는 어떤 식으로 사용되는지 알아보자.

 

먼저 OpenAPI 설정 코드를 추가한다.

// com.tistory.devs0n.scalar.OpenAPIConfiguration.kt
package com.tistory.devs0n.scalar

import io.swagger.v3.oas.models.Components
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.info.Info
import io.swagger.v3.oas.models.security.SecurityRequirement
import io.swagger.v3.oas.models.security.SecurityScheme
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class OpenAPIConfiguration {
    @Bean
    fun openApi(): OpenAPI {
        return OpenAPI()
            .info(Info().title("Scalar API Reference example API"))
            .components(
                Components().addSecuritySchemes(
                    "Access Token",
                    SecurityScheme()
                        .type(SecurityScheme.Type.HTTP)
                        .`in`(SecurityScheme.In.HEADER)
                        .name("Authorization")
                        .scheme("bearer")
                        .bearerFormat("JWT")

                )
            )
            .addSecurityItem(
                SecurityRequirement()
                    .addList("Access Token")
            )
    }
}

 

그리고 서버를 재실행 후 API 문서를 다시 보면 인증 토큰을 설정하는 란이 생긴 것을 확인할 수 있다.

 

API를 호출하는 창에서 인증 토큰을 그대로 사용하는 것을 확인할 수 있고 실제 요청 header에도 인증 토큰이 잘 전송되는 것을 볼 수 있다.

 

댓글