<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Spring Rest Docs on</title><link>https://taetaetae.github.io/tags/spring-rest-docs/</link><description>Recent content in Spring Rest Docs on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Tue, 22 Dec 2020 10:41:40 +0900</lastBuildDate><atom:link href="https://taetaetae.github.io/tags/spring-rest-docs/index.xml" rel="self" type="application/rss+xml"/><item><title>Swagger와 Spring Restdocs의 우아한 조합 (by OpenAPI Spec)</title><link>https://taetaetae.github.io/posts/a-combination-of-swagger-and-spring-restdocs/</link><pubDate>Tue, 22 Dec 2020 10:41:40 +0900</pubDate><guid>https://taetaetae.github.io/posts/a-combination-of-swagger-and-spring-restdocs/</guid><description>&lt;p>　﻿MSA 환경에서의 API 문서화는 어떤 식으로 구성하는 걸까? 예컨대, 모듈이 10개 있다고 하면 각 모듈마다 API 문서가 만들어질 테고 API 문서를 클라이언트에 제공하기 위해서 각각의 (10개의) URL를 전달해야 할 텐데 이게 과연 효율적일까? 물론 기능별로 URL이 분리된다는 장점이 있고 굳이 모아보자면 각 API 문서를 다시 한번 크롤링 하여 검색할 수 있도록 제공하는 것도 하나의 방법이 될 수 있다. 하지만 이러한 방법들은 요구 사항을 위한 별도의 작업을 하게 되니 일을 위한 일이 되는 것 같아 뭔가 아쉬웠다. 좋은 방법이 없을까?&lt;/p>
&lt;h2 id="고민의-시작">고민의 시작&lt;/h2>
&lt;p>　한창 궁금증이 머릿속에서 지워지지 않았을때 &lt;a href="https://www.facebook.com/groups/springkorea/permalink/2731936460251299/" target="_blank" rel="noopener noreffer ">Spring 한국 스프링 사용자 모임 페이스북 그룹&lt;/a>에 문의도 해가며 방법을 찾아가고 있었다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-1.png" title="/images/a-combination-of-swagger-and-spring-restdocs/line-1.png" data-thumbnail="/images/a-combination-of-swagger-and-spring-restdocs/line-1.png" data-sub-html="&lt;h2>﻿닉네임이나 프로필 사진은 그들의 개인 정보를 위해 임의로 지정하였다.&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-1.png"
 data-srcset="https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-1.png, https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-1.png 1.5x, https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-1.png 2x"
 data-sizes="auto"
 alt="/images/a-combination-of-swagger-and-spring-restdocs/line-1.png" width="80%" />
 &lt;/a>&lt;figcaption class="image-caption">﻿닉네임이나 프로필 사진은 그들의 개인 정보를 위해 임의로 지정하였다.&lt;/figcaption>
 &lt;/figure>
&lt;p>　﻿필자와 함께 개발자의 인생을 시작한 멋진 친구들에게 정확히 올해 6월 초에 고민을 털어놓으며 좋은 방법이 없을지에 대한 논의를 했던 적이 있다. 그런데 친구 중 한 명이 잊고 있었던 그 이슈에 대해서 다시 꺼내며 URL 하나를 던져준다. 참 고마운 친구들.&lt;/p>
&lt;blockquote>
&lt;p>Shout out 34. &lt;a href="http://asuraiv.tistory.com/" target="_blank" rel="noopener noreffer ">asuraiv&lt;/a>, &lt;a href="https://black9p.github.io/" target="_blank" rel="noopener noreffer ">black9p&lt;/a>&lt;/p>&lt;/blockquote>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-2.png" title="/images/a-combination-of-swagger-and-spring-restdocs/line-2.png" data-thumbnail="/images/a-combination-of-swagger-and-spring-restdocs/line-2.png" data-sub-html="&lt;h2>언 반년이 지났으나 필자도 잊고 있었던 이슈를 그는 기억하고 있었다.&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-2.png"
 data-srcset="https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-2.png, https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-2.png 1.5x, https://taetaetae.github.io/images/a-combination-of-swagger-and-spring-restdocs/line-2.png 2x"
 data-sizes="auto"
 alt="/images/a-combination-of-swagger-and-spring-restdocs/line-2.png" width="40%" />
 &lt;/a>&lt;figcaption class="image-caption">언 반년이 지났으나 필자도 잊고 있었던 이슈를 그는 기억하고 있었다.&lt;/figcaption>
 &lt;/figure>
&lt;p>　﻿올해 NHN FORWARD에서 진행했던 세션 중에서 &lt;a href="https://forward.nhn.com/session/3" target="_blank" rel="noopener noreffer ">MSA 환경에서 API 문서 관리하기: 생성부터 배포까지&lt;/a>라는 제목의 내용이었고, 정확하게 필자가 고민했던 부분을 콕! 집어서 해결해 준 사례였다. 역시 세상엔 엄청난 고수들이 내가 고민했던 부분들을 이미(혹은 이후에라도) 고민하고 해결한 경우가 많다는 것을 느끼고 공유의 힘이 이렇게도 대단하구나 하며 놀라움을 금치 못하였다.﻿&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/qguXHW0s8RY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video">&lt;/iframe>
 &lt;/div>

&lt;p>　﻿이번 포스팅에서는 OpenAPI Spec 을 활용하여 Spring Restdocs로 만들어지는 문서를 Swagger UI에서 보는 흐름을 실제로 구현해 보고자 한다. 즉, Swagger 나 Spring Restdocs 뭐로 만들든 간에 OpenAPI Spec에 맞춰서만 만든다면 한곳에서 볼 수 있겠다는 희망이 보였다. 며칠 전 작성한 &lt;a href="https://taetaetae.github.io/posts/openapi-and-swagger-ui-in-spring-boot/" rel="">OpenAPI 와 Swagger-ui 포스팅&lt;/a>을 본 독자들은 지금의 포스팅을 작성하기 위한 밑거름이었다는 사실을 눈치챘을 수도 있을 것 같다.&lt;/p>
&lt;blockquote>
&lt;p>﻿좋은 내용을 공유해 주신 (저의 고민을 완벽하게 해결해 주신) NHN FORWARD 발표자분께 이 포스팅을 빌어 감사의 인사를 보냅니다. :) 당장 팀 내에도 적용해봐야겠어요!!&lt;/p>&lt;/blockquote>
&lt;h2 id="spring-restdocs에서-openapi-spec-추출">﻿Spring Restdocs에서 OpenAPI Spec 추출&lt;/h2>
&lt;p>　﻿누가 또 친절하게 오픈소스로 만들어놨다. &lt;a href="https://github.com/ePages-de/restdocs-api-spec" target="_blank" rel="noopener noreffer ">https://github.com/ePages-de/restdocs-api-spec&lt;/a> 에서 관련 내용을 확인할 수가 있는데 해당 링크에서는 gradle 버전이고 &lt;a href="https://github.com/BerkleyTechnologyServices/restdocs-spec" target="_blank" rel="noopener noreffer ">https://github.com/BerkleyTechnologyServices/restdocs-spec&lt;/a> 는 maven 버전이라고 한다. 마침 필자의 Github에 Maven 버전으로 SpringRestdocs를 세팅해둔 &lt;a href="https://github.com/taetaetae/SpringRestDocs-In-SpringBoot" target="_blank" rel="noopener noreffer ">Repository&lt;/a> 가 있어서 이를 활용해보고자 한다.﻿&lt;/p>
&lt;h3 id="pomxml-추가">pom.xml 추가&lt;/h3>
&lt;p>　﻿관련 dependency를 추가하자. jcenter라고 bintray.com 에서 운영되는 Maven Repository에 올려진 오픈소스이니 repository 도 추가해 주자.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;restdocs-api-spec.version&amp;gt;&lt;/span>0.10.0&lt;span class="nt">&amp;lt;/restdocs-api-spec.version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;restdocs-spec.version&amp;gt;&lt;/span>0.19&lt;span class="nt">&amp;lt;/restdocs-spec.version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;repositories&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;repository&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="nt">&amp;lt;id&amp;gt;&lt;/span>jcenter&lt;span class="nt">&amp;lt;/id&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="nt">&amp;lt;url&amp;gt;&lt;/span>https://jcenter.bintray.com&lt;span class="nt">&amp;lt;/url&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;/repository&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/repositories&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;groupId&amp;gt;&lt;/span>com.epages&lt;span class="nt">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;artifactId&amp;gt;&lt;/span>restdocs-api-spec&lt;span class="nt">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;version&amp;gt;&lt;/span>${restdocs-api-spec.version}&lt;span class="nt">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;scope&amp;gt;&lt;/span>test&lt;span class="nt">&amp;lt;/scope&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;groupId&amp;gt;&lt;/span>com.epages&lt;span class="nt">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;artifactId&amp;gt;&lt;/span>restdocs-api-spec-mockmvc&lt;span class="nt">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;version&amp;gt;&lt;/span>${restdocs-api-spec.version}&lt;span class="nt">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;scope&amp;gt;&lt;/span>test&lt;span class="nt">&amp;lt;/scope&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>﻿위의 dependency에서 제공해 주는 모듈로 테스트의 SpringRestdocs를 만들었다면 OpenAPI Spec 을 만들어 주는 plugin 또한 추가해 주자&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;pluginRepositories&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;pluginRepository&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="nt">&amp;lt;id&amp;gt;&lt;/span>jcenter&lt;span class="nt">&amp;lt;/id&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="nt">&amp;lt;url&amp;gt;&lt;/span>https://jcenter.bintray.com&lt;span class="nt">&amp;lt;/url&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;/pluginRepository&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/pluginRepositories&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;plugin&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;groupId&amp;gt;&lt;/span>com.github.berkleytechnologyservices.restdocs-spec&lt;span class="nt">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;artifactId&amp;gt;&lt;/span>restdocs-spec-maven-plugin&lt;span class="nt">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;version&amp;gt;&lt;/span>${restdocs-spec.version}&lt;span class="nt">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;executions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="nt">&amp;lt;execution&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">			&lt;span class="nt">&amp;lt;goals&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">				&lt;span class="nt">&amp;lt;goal&amp;gt;&lt;/span>generate&lt;span class="nt">&amp;lt;/goal&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">			&lt;span class="nt">&amp;lt;/goals&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">			&lt;span class="nt">&amp;lt;configuration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">				&lt;span class="nt">&amp;lt;specification&amp;gt;&lt;/span>OPENAPI_V3&lt;span class="nt">&amp;lt;/specification&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">				&lt;span class="nt">&amp;lt;format&amp;gt;&lt;/span>JSON&lt;span class="nt">&amp;lt;/format&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">				&lt;span class="nt">&amp;lt;outputDirectory&amp;gt;&lt;/span>${project.build.directory}/classes/static/docs&lt;span class="nt">&amp;lt;/outputDirectory&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">			&lt;span class="nt">&amp;lt;/configuration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="nt">&amp;lt;/execution&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;/executions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/plugin&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>﻿위 plugin 설정을 보면 format 을 JSON으로 한 것을 볼 수 있는데 YAML로도 만들 수 있다. 자세한 사용방법은 위에서 명시한 링크를 참고해보는 게 좋을 것 같다.&lt;/p></description></item><item><title>SpringRestDocs를 SpringBoot에 적용하기</title><link>https://taetaetae.github.io/2020/03/08/spring-rest-docs-in-spring-boot/</link><pubDate>Sun, 08 Mar 2020 23:16:59 +0000</pubDate><guid>https://taetaetae.github.io/2020/03/08/spring-rest-docs-in-spring-boot/</guid><description>&lt;p>API를 개발하고 제공하기 위해서는 그에 해당하는 API 명세를 작성해서 사용하는 곳에 전달하게 된다. 어떤 URL에 어떤 파라미터를 사용해서 어떻게 요청을 하면 어떤 결과를 응답으로 내려주는지에 대한 관련 정보들. 이러한 &amp;ldquo;API 문서&amp;rdquo; 를 제공하는 방식은 상황에 따라 다양한 방법으로 사용되곤 한다. &lt;!--more -->&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/spring-rest-docs-in-spring-boot/api-document.jpg" title="/images/spring-rest-docs-in-spring-boot/api-document.jpg" data-thumbnail="/images/spring-rest-docs-in-spring-boot/api-document.jpg" data-sub-html="&lt;h2>API 코드와 해당 문서의 동기화가 자동으로 되어야 조금 편해질것 같다는 생각이 들었다. 출처 : https://dribbble.com/shots/3386291-API-Documentation&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/spring-rest-docs-in-spring-boot/api-document.jpg"
 data-srcset="https://taetaetae.github.io/images/spring-rest-docs-in-spring-boot/api-document.jpg, https://taetaetae.github.io/images/spring-rest-docs-in-spring-boot/api-document.jpg 1.5x, https://taetaetae.github.io/images/spring-rest-docs-in-spring-boot/api-document.jpg 2x"
 data-sizes="auto"
 alt="/images/spring-rest-docs-in-spring-boot/api-document.jpg" width="50%" />
 &lt;/a>&lt;figcaption class="image-caption">API 코드와 해당 문서의 동기화가 자동으로 되어야 조금 편해질것 같다는 생각이 들었다. &lt;br>출처 : &lt;a href="https://dribbble.com/shots/3386291-API-Documentation" target="_blank" rel="noopener noreffer ">https://dribbble.com/shots/3386291-API-Documentation&lt;/a>&lt;/figcaption>
 &lt;/figure>
&lt;p>필자는 주로 &amp;ldquo;위키&amp;rdquo;(또는 일반 문서)를 활용해서 전달하곤 했었는데 API의 형태가 달라질 때마다 해당 위키를 수정해야만 하는 번거로움이 있었다. API 수정하면 위키도 수정하고. 깜박하고 위키 수정을 안하게 될 경우 왜 API 명세가 다르냐는 문의가&amp;hellip; 그러다 알게된 Spring Rest Docs. (아무리 좋은 기술, 좋은 툴 이라 해도 실제로 본인이 필요로 하고 사용을 해야하는 이유가 생길때 비로소 빛을 발하는것 같은 느낌이다.)&lt;/p>
&lt;blockquote>
&lt;p>이 포스팅에서는 swegger 와 비교하는 내용은 제외할까 한다. 워낙 유명한 두 양대 산맥(?)이라 검색해보면 각각의 장단점이 자세히 나와있기에&amp;hellip;&lt;/p>&lt;/blockquote>
&lt;p>최근 들어 TestCode 의 중요성을 절실하게 느끼고 있었고, TestCode 를 작성하면 자연스럽게 문서를 만들어 주는 부분이 가장 매력적이라고 생각이 들었다. 이를 반대로 생각하면, TestCode 가 실패할 경우 빌드 자체가 안되기에 어쩔수 없이 TestCode를 성공시켜야만 하고, 자연스럽게 정상적인(최신화 된) API 문서가 만들어지게 된다.&lt;/p>
&lt;p>이번 포스팅에서는 다음과 같은 목표를 두고 실무에서 언제든지 활용이 가능한 약간의 &amp;ldquo;가이드&amp;rdquo; 같은 내용으로 작성해 보고자 한다.&lt;/p>
&lt;ul>
&lt;li>Spring Boot 최신 버전에서 Spring Rest Docs 를 설정한다.&lt;/li>
&lt;li>임의의 API 를 만들고 그에 따른 TestCase 를 작성한다.&lt;/li>
&lt;li>Spring.profile 에 따라 Spring Rest Docs Url 을 접근 가능/불가능 할 수 있게 한다.&lt;/li>
&lt;/ul>
&lt;p>물론 필자의 방법이 다를수도 있지만, 이러한 방법을 토대로 보다 더 우아하고 아름다운 방법을 알아갈수 있지 않을까 하는 기대로.&lt;/p>
&lt;h2 id="spring-boot-에-spring-rest-docs-셋팅하고-testcase-작성하기">Spring Boot 에 Spring Rest Docs 셋팅하고 TestCase 작성하기&lt;/h2>
&lt;p>우선 Spring Boot 프로젝트를 만든다. &lt;a href="https://start.spring.io/" target="_blank" rel="noopener noreffer ">https://start.spring.io/&lt;/a> 에서 만들어도 되고 IDE 에서 제공하는 툴로 만들어도 되고. 만드는 방식은 무방하다. 그 다음 필요한 dependency 를 추가해 준다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;groupId&amp;gt;&lt;/span>org.springframework.restdocs&lt;span class="nt">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;artifactId&amp;gt;&lt;/span>spring-restdocs-mockmvc&lt;span class="nt">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nt">&amp;lt;scope&amp;gt;&lt;/span>test&lt;span class="nt">&amp;lt;/scope&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>임의로 API를 작성하고&lt;/p>
&lt;ul>
&lt;li>모델&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Getter&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nd">@Setter&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">Book&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Integer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">author&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>컨트롤러&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@RestController&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">BookController&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="nd">@GetMapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;/book/{id}&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Book&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">getABook&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nd">@PathVariable&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Integer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">		&lt;/span>&lt;span class="n">Book&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">book&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Book&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">		&lt;/span>&lt;span class="n">book&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setId&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">		&lt;/span>&lt;span class="n">book&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setTitle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;spring rest docs in spring boot&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">		&lt;/span>&lt;span class="n">book&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setAuthor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;taetaetae&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">		&lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">book&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>해당 컨트롤러에 대한 TestCase 를 작성하자.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@WebMvcTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BookController&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nd">@AutoConfigureRestDocs&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// (1)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">BookControllerTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="nd">@Autowired&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">MockMvc&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mockMvc&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// (2)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">test_책을_조회하면_null이_아닌_객체를_리턴한다&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Exception&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">		&lt;/span>&lt;span class="n">mockMvc&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">perform&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;/book/{id}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">			&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">accept&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">MediaType&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">APPLICATION_JSON&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">			&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">andDo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">MockMvcResultHandlers&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">print&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">			&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">andExpect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">MockMvcResultMatchers&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">status&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">isOk&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">			&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">andDo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">document&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;book&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// (3)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">				&lt;/span>&lt;span class="n">pathParameters&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">					&lt;/span>&lt;span class="n">parameterWithName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">description&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;book unique id&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// (4)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">				&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">				&lt;/span>&lt;span class="n">responseFields&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">					&lt;/span>&lt;span class="n">fieldWithPath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">description&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;book unique id&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">					&lt;/span>&lt;span class="n">fieldWithPath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">description&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">					&lt;/span>&lt;span class="n">fieldWithPath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;author&amp;#34;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">description&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;author&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">				&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">			&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">			&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">andExpect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">jsonPath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;$.id&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">is&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">notNullValue&lt;/span>&lt;span class="p">())))&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// (5)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">			&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">andExpect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">jsonPath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;$.title&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">is&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">notNullValue&lt;/span>&lt;span class="p">())))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">			&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">andExpect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">jsonPath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;$.author&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">is&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">notNullValue&lt;/span>&lt;span class="p">())));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">	&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(1) Spring Boot 에서는 해당 어노테이션으로 여러줄에 걸쳐 설정해야 할 Spring Rest Docs 관련 설정을 아주 간단하게 해결할 수 있게 된다. (&lt;a href="https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs" target="_blank" rel="noopener noreffer ">참고&lt;/a>)&lt;/p>
&lt;p>(2) &lt;a href="https://docs.spring.io/spring-restdocs/docs/2.0.4.RELEASE/reference/html5/#getting-started-sample-applications" target="_blank" rel="noopener noreffer ">공식 도큐먼트&lt;/a> 에서는 4가지 방식을 말하고 있는데 이 포스팅 에서는 &amp;ldquo;MockMvc&amp;rdquo; 을 사용하고자 한다.&lt;/p>
&lt;p>(3) &amp;ldquo;book&amp;rdquo; 이라는 identifier 를 지정하면 해당 TestCase 가 수행될때 snippets 가 생성되는데 해당 identifier 묶음으로 생성이 된다.&lt;/p></description></item></channel></rss>