Miracle Morning, LHWN

16-2. Spring REST Docs - 실제 사용해보기 본문

IT 기술/[JAVA] Spring Boot

16-2. Spring REST Docs - 실제 사용해보기

Lee Hye Won 2021. 5. 29. 11:44

# 앞서 만들어주었던 API 에 대한 테스트 코드를 작성한다.

아래와 같이 /api/user/{id} 요청에 대한 응답 명세를 작성해주고, 실행하면 generated-snippets 하위 폴더에

각 요청/응답에 대한 snippet 들이 생성된다.

// test/java/com/spring/SpringRESTDocsPractice/UserApiDocumentation.java

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserApiDocumentation {
    @Rule
    public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
                .apply(documentationConfiguration(this.restDocumentation))
                .build();
    }

    @Test
    public void testRead() throws Exception {
        this.mockMvc.perform(get("/api/user/{id}", 1))
                .andDo(print())
                .andDo(document("user",
                        pathParameters(
                                parameterWithName("id").description("사용자 id")
                        ),
                        responseFields(
                                fieldWithPath("resultCode").description("응답코드"),
                                fieldWithPath("data.id").description("id"),
                                fieldWithPath("data.account").description("계정"),
                                fieldWithPath("data.email").description("이메일"),
                                fieldWithPath("data.phoneNumber").description("전화번호"),
                                fieldWithPath("data.createdAt").description("생성시간"),
                                fieldWithPath("data.updatedAt").description("수정시간")
                        )
                ));
    }

}

이제 생성된 이 snippets 들을 조합해서 asciidoc 파일을 만든다.

 

// src/docs/asciidocs/user.docs

:basedir: {docdir}/../../../
:snippets: {basedir}/build/generated-snippets

= RESTful Notes API Guide
:doctype: user
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 4
:sectnums:
:sectlinks:
:sectanchors:

[[api]]
== User Api

include::{snippets}/user/curl-request.adoc[]
include::{snippets}/user/http-request.adoc[]
include::{snippets}/user/path-parameters.adoc[]
include::{snippets}/user/http-response.adoc[]
include::{snippets}/user/response-fields.adoc[]

이렇게 문법 규칙에 맞게 작성을 해주면 아래와 같은 결과가 나타난다. 여기서는 결과를 편하게 보기 위해 Asciidoc Plugin 을 사용했다.

 

이러한 API Guide 를 호스팅해서 보기 위해서는 build.gradle 에 copy 속성을 추가해주면 된다.

asciidoctor {
	inputs.dir snippetsDir
	dependsOn test
}

bootJar {
	dependsOn asciidoctor

	copy {
		from "build/asciidoc/html5"
		into "src/main/resources/static/docs/"
	}
}

http://localhost:8080/docs/user.html

 

# 이제 openapi3 를 이용해서 Swagger UI 에 띄워볼 것이다.

// build.gradle

openapi3 {
	server = "http://localhost:8080"
	title = 'My API'
	description = 'My API Description'
	version = '0.1.0'
	format = 'yaml'

	copy {
		from "build/api-spec"
		into "src/main/resources/static/docs/"
	}
}
// UserApiDocumentation.java 의 testRead() 메서드

...
this.mockMvc.perform(get("/api/user/{id}", 1))
                .andDo(document("user",
                        preprocessRequest(prettyPrint()),
                        preprocessResponse(prettyPrint()),
                        resource(
                                ResourceSnippetParameters.builder()
                                .description("사용자의 정보를 생성/조회/수정/삭제 합니다.")
                                .summary("사용자 정보")
                                .pathParameters(
                                        parameterWithName("id").description("사용자 id")
                                )
                                .responseFields(
                                        fieldWithPath("resultCode").description("응답코드"),
                                        fieldWithPath("data.id").description("id"),
                                        fieldWithPath("data.account").description("계정"),
                                        fieldWithPath("data.email").description("이메일"),
                                        fieldWithPath("data.phoneNumber").description("전화번호"),
                                        fieldWithPath("data.createdAt").description("생성시간"),
                                        fieldWithPath("data.updatedAt").description("수정시간")
                                )
                                .build()
                        )
                ));
    }
    ...

위에서 설정한 openapi3 를 실행하면 /build/api-spec/openapi3.yaml 파일이 생성된다.

// openapi3.yaml

openapi: 3.0.1
info:
  title: My API
  description: My API Description
  version: 0.1.0
servers:
- url: http://localhost:8080
tags: []
paths:
  /api/user/{id}:
    get:
      tags:
      - api
      summary: 사용자 정보
      description: 사용자의 정보를 생성/조회/수정/삭제 합니다.
      operationId: user
      parameters:
      - name: id
        in: path
        description: 사용자 id
        required: true
        schema:
          type: string
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/api-user-id1028051256'
              examples:
                user:
                  value: "{\n  \"resultCode\" : \"OK\",\n  \"data\" : {\n    \"id\"\
                    \ : 1,\n    \"account\" : \"test\",\n    \"email\" : \"test@naver.com\"\
                    ,\n    \"phoneNumber\" : \"010-1234-1234\",\n    \"createdAt\"\
                    \ : \"2021-05-28T06:00:47\",\n    \"updatedAt\" : \"2021-05-28T06:00:47\"\
                    \n  }\n}"
components:
  schemas:
    api-user-id1028051256:
      type: object
      properties:
        data:
          type: object
          properties:
            createdAt:
              type: string
              description: 생성시간
            phoneNumber:
              type: string
              description: 전화번호
            id:
              type: number
              description: id
            email:
              type: string
              description: 이메일
            account:
              type: string
              description: 계정
            updatedAt:
              type: string
              description: 수정시간
        resultCode:
          type: string
          description: 응답코드

 

이후 프로젝트를 실행하여 http://localhost:8080/docs/openapi3.yaml 을 실행하면 ‘openapi3.yaml’ 파일이 다운로드 된다.

# Docker 를 이용하여 Swagger UI 를 설치 후 띄워볼 것이다.

docker 를 80 포트 (내부적으로 8080)에서 띄우고,

아까 만들었던 openapi3.yaml 파일을 'name' 이라는 이름으로, 그리고 swagger 의 기본 openapi 를 'sample' 이라는 이름으로 띄운다.

 

이후 localhost 를 브라우저에서 찍어보면 도메인이 달라서 아래와 같은 오류가 발생한다.

따라서 모든 도메인을 허용해주기 위해 WebConfig 파일을 만들어 addMapping("/**") 을 추가해주고 다시 로드한다.

package com.spring.SpringRESTDocsPracticce;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

http://localhost/

이전에 데이터베이스에 id=1 값에 대한 데이터를 넣어놨으니 해당 데이터를 기준으로 조회 테스트를 해보면 아래와 같은 결과가 나온다.

그리고 intellij 에서도 맨 아랫줄을 보면 실제 API 가 호출된 것을 볼 수 있다.

아까 URL 배열에 두 번째 요소로 지정한 sample 기본 API 문서도 아래와 같이 활용할 수 있다.

 

Comments