์ƒˆ์†Œ์‹

Java/Spring

OpenApi Spec์„ ์ด์šฉํ•œ RestDocs to Swagger ๋ณ€ํ™˜ ์ž๋™ํ™”

  • -
728x90
๋ฐ˜์‘ํ˜•

๐Ÿคจ RestDocs์™€ Swagger์˜ ์žฅ์ ๊ณผ ๋‹จ์ 

๋ฐ๋ธŒ์ฝ”์Šค ์ตœ์ข… ํ”„๋กœ์ ํŠธ๋ฅผ ์ค€๋น„ํ•˜๋ฉด์„œ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ ์ง„ํ–‰์ค‘์— API ๋ฌธ์„œํ™”๋ฅผ RestDocs๋กœ ์ง„ํ–‰ํ• ์ง€ Swagger๋กœ ์ง„ํ–‰ํ• ์ง€ ๊ณ ๋ฏผ์ค‘์ธ ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค.

์ด์ „์— Spring RestDocs๋Š” ์‚ฌ์šฉํ•ด๋ณด์•˜์ง€๋งŒ Swagger๋Š” ์‚ฌ์šฉํ•ด๋ณธ์ ์ด ์—†์—ˆ๊ณ  Swagger์— ๋Œ€ํ•ด์„œ ๋Œ€๊ฐ• ์•Œ๊ธฐ๋กœ๋Š” ํŽ˜์ด์ง€์—์„œ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด ํ”„๋ก ํŠธ์—”๋“œ์— ์ข€ ๋” ์นœํ™”์ ์ด๋ผ๋Š” ์ด์•ผ๊ธฐ๋ฅผ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์— API ๋ฌธ์„œํ™”๋ฅผ ํ•˜๊ธฐ ์ด์ „์— ์ด๋“ค์˜ ์žฅ์ ๊ณผ ๋‹จ์ ์— ๋Œ€ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

  • Spring RestDocs
์žฅ์  ๋‹จ์ 
ํ…Œ์ŠคํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ ๋ขฐ์„ฑ์ด ๋†’์Œ ์ถ”๊ฐ€์ ์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ๋งŽ์Œ
ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์•„ ๊น”๋”ํ•จ API ํ…Œ์ŠคํŠธ ๊ธฐ๋Šฅ์ด ์—†์Œ
  • Swagger
์žฅ์  ๋‹จ์ 
API ํ…Œ์ŠคํŠธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— API๋ฅผ ์ดํ•ดํ•˜๋Š”๋ฐ ๋„์›€์„ ์คŒ ์„ค์ •์ด ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์— ์ถ”๊ฐ€๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง
ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋จ ํ…Œ์ŠคํŠธ ๊ธฐ๋ฐ˜์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์„œ์˜ ์‹ ๋ขฐ๋„๊ฐ€ ๋–จ์–ด์ง
๊ฐ์ฒด์— ๋Œ€ํ•œ ์ •๋ณด๋„ ์ถ”๊ฐ€ ์ž‘์„ฑ ๊ฐ€๋Šฅํ•จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ฌด๊ฑฐ์›€

๋ฐฑ์—”๋“œ๋งŒ ์ž‘์—…ํ•˜๋ฉด Spring RestDocs๋กœ ์ถฉ๋ถ„ํ• ํ…Œ์ง€๋งŒ ํ”„๋ก ํŠธ์™€ ๊ฐ™์ด ํ˜‘์—…ํ•˜๋ฉด์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— API ํ…Œ์ŠคํŠธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” Swagger๊ฐ€ ๋” ์ข‹๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ Swagger์˜ ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ ๋ขฐ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์–ด ์ด๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์•ˆ์— ๋Œ€ํ•ด ์ฐพ์•„๋ณด๊ฒŒ ๋˜์—ˆ๊ณ  OpenApi spec์„ ์ด์šฉํ•˜์—ฌ RestDocs๋กœ ์ž‘์„ฑํ•œ ๊ฒƒ์„ Swagger๋กœ ๋ณ€ํ™˜ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

โš ๏ธ OpenApi Spec

OpenApi Spec์„ ์ด์šฉํ•˜์—ฌ Restdocs๋กœ ์ž‘์„ฑํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ Swagger๋กœ ๋ณ€ํ™˜์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์€ ์ฒดํฌํ–ˆ์œผ๋‚˜ OpenApi Spec์ด๋ผ๋Š”๊ฒŒ ๋ฌด์—‡์ผ๊นŒ์š”?

๋จผ์ € Open Api์™€ OpenApi๋Š” ์„œ๋กœ ๋‹ค๋ฅด๋‹ค๋Š” ์ ์„ ์•Œ์•„์•ผํ•ฉ๋‹ˆ๋‹ค.

Open Api์˜ ๊ฒฝ์šฐ ๊ฐœ๋ฐฉ๋œ API๋ผ๋Š” ์˜๋ฏธ๋กœ ๋ˆ„๊ตฌ๋˜์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๊ฐœ๋ฐฉ๋œ ์ƒํƒœ์˜ API๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๊ณต๊ณต๋ฐ์ดํ„ฐํฌํ„ธ์— ๋“ค์–ด๊ฐ€๋ฉด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” API๋“ค์ด Open API๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด์— OpenApi์˜ ๊ฒฝ์šฐ OAS(OpenAPI Specification)๋ผ๊ณ ๋„ ๋ถ€๋ฅด๋Š”๋ฐ RESTful API๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ API Spec์„ JSON์ด๋‚˜ YAML๋กœ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ์‹์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, OpenApi๋Š” Restful API ๋””์ž์ธ์— ๋Œ€ํ•œ ์ •์˜ ํ‘œ์ค€์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

โ™ป๏ธ RestDocs๋ฅผ ์ž‘์„ฑํ•˜๋ฉด Swagger๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋„๋ก ์ž๋™ํ™”

RestDocs์˜ ๊ฒฝ์šฐ ์‹ ๋ขฐ์„ฑ์ด ๋†’์ง€๋งŒ ๊ฐ€๋…์„ฑํ•˜๊ณ  API Test ์ œ๊ณต ๋“ฑ Swagger์— ์žˆ์–ด ํ˜‘์—…์— ์•„์‰ฌ์šด์ ์ด ์กด์žฌํ•œ๋‹ค๊ณ  ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์— Open API spec์„ ์ด์šฉํ•˜์—ฌ Swagger๋กœ ์ž๋™ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•ด ์ฝ”๋“œ ์ž‘์„ฑ์€ RestDocs๋กœ ํ•˜๊ณ  ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์€ Swagger๋กœ ํ•˜๊ฒŒ๋” ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ด์ œ ์ด ๊ณผ์ •์„ ์‹ค์ œ๋กœ ์ ์šฉํ•ด๋ด…์‹œ๋‹ค.

๋จผ์ € ์ ์šฉํ•œ ํ™˜๊ฒฝ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๐Ÿš€ ์–ธ์–ด : Java 17 ํ”„๋ ˆ์ž„์›Œํฌ : Spring boot 2.7.1 ๋นŒ๋“œ ํˆด : Gradle

Gradle์— API ๋ฌธ์„œํ™”์™€ ์ž๋™ ๋ณ€ํ™˜์— ํ•„์š”ํ•œ ๋‹ค์Œ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

// build.gradle
plugins {
	...
	...
	id 'com.epages.restdocs-api-spec' version '0.16.0'
}

dependencies {
		...
		...
    testImplementation 'com.epages:restdocs-api-spec-mockmvc:0.16.2'
}

Restdocs๋กœ ๋ณ€ํ™˜ํ•œ OpenAPI์˜ ์ •๋ณด๋ฅผ Gradle์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

// build.gradle
openapi3 {
    server = 'http://localhost:8080' // ์ž์‹  ์„œ๋ฒ„์˜ URL ์ž‘์„ฑ
    title = 'RestDocs to Swagger ๋ณ€ํ™˜ ํ…Œ์ŠคํŠธ' // Swagger ์ž‘๋™์‹œ ํŽ˜์ด์ง€์— ๋‚˜์˜ค๋Š” ์ œ๋ชฉ
    description = 'Restdocs๋กœ API ๋ฌธ์„œ ์ž‘์„ฑ ํ›„ ์ด๋ฅผ Swagger๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํŽ˜์ด์ง€' // Swagger ํŽ˜์ด์ง€ ์ œ๋ชฉ ๋ฐ‘์— ์„ค๋ช…๋ž€์— ์ถ”๊ฐ€๋˜๋Š” ๋ฉ”์„ธ์ง€
    version = '0.0.1-SNAPSHOT' // ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฒ„์ „ ์ •๋ณด
    format = 'yaml' // json์œผ๋กœ๋„ ๊ฐ€๋Šฅ
}

ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํ›„ snippet์œผ๋กœ ์ƒ์„ฑ๋œ openapi3.yaml ํŒŒ์ผ์„ static ์˜์—ญ์— ์˜ฎ๊ธธ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

// build.grade
task copyTest {
    dependsOn("openapi3")
    copy {
            from "$buildDir/api-spec/openapi3.yaml"
            into "src/main/resources/static/docs/."
        }
}

์ด์ œ ๋ณ€ํ™˜๋œ OpenAPI๋ฅผ Swagger UI๋กœ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด Swagger-UI๋ฅผ ๋‹ค์šด๋ฐ›์Šต๋‹ˆ๋‹ค.

https://swagger.io/docs/open-source-tools/swagger-ui/usage/installation/

 

Swagger Documentation

Installation Distribution channels NPM Registry We publish two modules to npm: swagger-ui and swagger-ui-dist. swagger-ui is meant for consumption by JavaScript web projects that include module bundlers, such as Webpack, Browserify, and Rollup. Its main fi

swagger.io

๋‹ค์šด ๋ฐ›์€ Swagger-ui์—์„œ /dist ํด๋” ํ•˜์œ„์— ์žˆ๋Š” ํŒŒ์ผ๋“ค์„ src/main/resources/static/docs ๊ฒฝ๋กœ๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค.

๋‹ค์šด ๋ฐ›์€ ํŒŒ์ผ์ค‘์— ํ•„์š” ์—†๋Š” ํŒŒ์ผ์ธ ๋‹ค์Œ ํŒŒ์ผ์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

  • oauth2-redirect.html
  • swagger-ui.js
  • swagger-ui-es-bundle-core.js
  • swagger-ui-es-bundle.js

์‚ญ์ œ๋ฅผ ์™„๋ฃŒํ–ˆ์œผ๋ฉด index.html์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Swagger UI</title>
  <link rel="stylesheet" type="text/css" href="/static/docs/swagger-ui.css" />
  <link rel="icon" type="image/png" href="/static/docs/favicon-32x32.png" sizes="32x32" />
  <link rel="icon" type="image/png" href="/static/docs/favicon-16x16.png" sizes="16x16" />
  <style>
    html
    {
      box-sizing: border-box;
      overflow: -moz-scrollbars-vertical;
      overflow-y: scroll;
    }

    *,
    *:before,
    *:after
    {
      box-sizing: inherit;
    }

    body
    {
      margin:0;
      background: #fafafa;
    }
  </style>
</head>

<body>
<div id="swagger-ui"></div>

<script src="/static/docs/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="/static/docs/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
  window.onload = function() {
    // Begin Swagger UI call region
    const ui = SwaggerUIBundle({
      url: "/static/docs/openapi3.yaml",
      dom_id: '#swagger-ui',
      deepLinking: true,
      presets: [
        SwaggerUIBundle.presets.apis,
        SwaggerUIStandalonePreset
      ],
      plugins: [
        SwaggerUIBundle.plugins.DownloadUrl
      ],
      layout: "StandaloneLayout"
    });
    // End Swagger UI call region

    window.ui = ui;
  };
</script>
</body>
</html>

์ด์ œ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ ์šฉ๋„๋กœ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค.

@RestController
@RequestMapping("/user")
public class MainController {

    @GetMapping
    public ResponseEntity<MainResponse.Get> get() {
        return ResponseEntity.ok(
            new MainResponse.Get("get test success")
        );
    }
}

ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ์— ๋Œ€ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค์‹œ๋‹ค.

@WebMvcTest(MainController.class)
@AutoConfigureMockMvc
@AutoConfigureRestDocs
class MainControllerTest {

    @Autowired
    private MockMvc mockMvc;

    private final ObjectMapper mapper = new ObjectMapper();

    @Test
    @DisplayName("Get ํ…Œ์ŠคํŠธ")
    void getTest() throws Exception {
        mockMvc.perform(
                RestDocumentationRequestBuilders.get("/user")
            )
            .andExpect(status().isOk())
            .andDo(MockMvcRestDocumentationWrapper.document("test-get",
                ResourceSnippetParameters.builder()
                    .tag("ํ…Œ์ŠคํŠธ")
                    .summary("Get ํ…Œ์ŠคํŠธ")
                    .description("Get ํ…Œ์ŠคํŠธ")
                    .responseSchema(Schema.schema("MainResponse.Get"))
                    ,
                preprocessRequest(prettyPrint()),
                preprocessResponse(prettyPrint()),
                responseFields(
                    fieldWithPath("message").type(JsonFieldType.STRING).description("๋ฉ”์„ธ์ง€")
                )
            ));

    }
}

ํ˜„์žฌ static์— ๋„ฃ์–ด๋‘” ์Šค์›จ๊ฑฐ UI์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‹ค์Œ ์„ค์ •์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

@Configuration
public class StaticRoutingConfigure implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}โ€‹


์ž‘์„ฑ๋œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•œ ํ›„ build.gradle์—์„œ ์ž‘์„ฑํ•œ copyTest๋ฅผ ์‹คํ–‰์‹œํ‚ต๋‹ˆ๋‹ค. ๋งŒ์•ฝ src/main/resources/static/docs/openapi3.yaml์ด ์ƒ์„ฑ๋ฌ๋‹ค๋ฉด ์ž˜ ๋™์ž‘๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๊ณ  http://{domainname}/docs/index.html๋กœ ์ด๋™ํ–ˆ์„ ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ™”๋ฉด์ด ๋‚˜์˜จ๋‹ค๋ฉด ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

๐Ÿง‘‍๐Ÿ’ป Swagger ํ™”๋ฉด ์ปค์Šคํ…€ํ•˜๊ธฐ

OpenApi๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ RestDocs๋กœ ์ง  ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ Swagger๋กœ ์ž๋™๋ณ€ํ™˜ ํ•ด์ฃผ๋Š” ๊ฒƒ์€ ๊ฐ„ํŽธํ•˜์ง€๋งŒ Restdocs ๋ฌธ๋ฒ•์œผ๋กœ๋งŒ OpenApi Spec์„ ์ด์šฉํ•˜์—ฌ Swagger ์ž๋™๋ณ€ํ™˜์„ ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด๋‹น API์— ๋Œ€ํ•œ ์„ค๋ช…์ด ๋นˆ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์Šคํ‚ค๋งˆ์˜ ๊ฒฝ์šฐ Request์™€ Response์— ๋Œ€ํ•œ ๊ฐ์ฒด ๋‚ด์šฉ์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋Š”๋ฐ ์œ„์™€ ๊ฐ™์ด ํ‘œํ˜„๋˜๋ฉด ์ด๊ฒŒ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ธ์ง€ ์•Œ๊ธฐ ํž˜๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ์„ ํ• ๋•Œ ResourceSnippetParameters ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ปค์Šคํ…€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € RestDocs๋กœ๋งŒ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

@Test
@DisplayName("Post ํ…Œ์ŠคํŠธ")
void postTest() throws Exception {
    MainRequest.Post request = new Post("post request");
    mockMvc.perform(
            RestDocumentationRequestBuilders.post("/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(mapper.writeValueAsString(request))
        )
        .andExpect(status().isCreated())
        .andDo(MockMvcRestDocumentationWrapper.document("test-post",
            preprocessRequest(prettyPrint()),
            preprocessResponse(prettyPrint()),
            requestFields(
                fieldWithPath("message").type(JsonFieldType.STRING).description("์š”์ฒญ ๋ฉ”์‹œ์ง€")
            ),
            responseFields(
                fieldWithPath("id").type(JsonFieldType.NUMBER).description("์ƒ์„ฑ ID")
            )));
}

์ผ๋ฐ˜์ ์ธ Restdocs์™€ ๋‹ค๋ฅธ์ ์€ MockMvcRestDocumentationWrapper ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ API ๋ฌธ์„œํ™”๋ฅผ ์‹œํ‚จ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

๋งŒ์•ฝ, ์ด์—๋Œ€ํ•ด์„œ ์ปค์Šคํ…€ ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ResourceSnippetParameters ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

...
...
.andExpect(status().isCreated())
  .andDo(MockMvcRestDocumentationWrapper.document("test-post",
      ResourceSnippetParameters.builder()
          .tag("ํ…Œ์ŠคํŠธ")
          .summary("Post ํ…Œ์ŠคํŠธ")
          .description("Post ํ…Œ์ŠคํŠธ")
          .requestSchema(Schema.schema("MainRequest.Post"))
          .responseSchema(Schema.schema("MainResponse.Post"))
      ,
      preprocessRequest(prettyPrint()),
      preprocessResponse(prettyPrint()),
...
...

  • ResourceSnippetParameters.builder()
    ์ง์ ‘ ์ž‘์„ฑํ•  API ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • tag(String)
    ์œ„์˜ ์ด๋ฏธ์ง€์—์„œ “ํ…Œ์ŠคํŠธ"์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ์—ฌ๋ŸฌAPI๋ฅผ ๋ฌถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • summary(String)
    API์˜ ์š”์ฒญ URL ์˜†์— ๋“ค์–ด๊ฐ€๋Š” ์ œ๋ชฉ์ž…๋‹ˆ๋‹ค.
  • description(String)
    API ์„ธ๋ถ€ ์ •๋ณด๋กœ ๋“ค์–ด๊ฐ”์„ ๋•Œ ์กด์žฌํ•˜๋Š” ์„ค๋ช…์ž…๋‹ˆ๋‹ค.
  • requestSchema(Schema)
    ํ•ด๋‹น API๋ฅผ ํ˜ธ์ถœํ• ๋•Œ ์‚ฌ์šฉํ•œ ๋ณธ๋ฌธ๊ณผ ๋งคํ•‘๋˜๋Š” ๊ฐ์ฒด์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
  • responseSchema(Schema)
    ํ•ด๋‹น API์˜ ๋ฐ˜ํ™˜ ๊ฐ’์˜ ๋ณธ๋ฌธ๊ณผ ๋งคํ•‘๋˜๋Š” ๊ฐ์ฒด์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.

๐Ÿ“ ์˜ˆ์ œ ์ฝ”๋“œ

https://github.com/zxcv9203/openapi_spec_restdocs_example.git

 

GitHub - zxcv9203/openapi_spec_restdocs_example

Contribute to zxcv9203/openapi_spec_restdocs_example development by creating an account on GitHub.

github.com

๐Ÿง ์ฐธ๊ณ ์ž๋ฃŒ

https://gruuuuu.github.io/programming/openapi/

https://velog.io/@bread_dd/Spring-Rest-Docs์™€-Open-Api-Swagger

https://taetaetae.github.io/posts/a-combination-of-swagger-and-spring-restdocs/

https://github.com/ePages-de/restdocs-api-spec

https://github.com/traeper/api_documentation

 

๋ฐ˜์‘ํ˜•
Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.