#14 simple blog : spring rest docs custom

This commit is contained in:
haerong22
2022-07-30 06:14:17 +09:00
parent 0e0e9a7a3b
commit 6750a3f7f2
4 changed files with 264 additions and 27 deletions

View File

@@ -1,13 +1,35 @@
= Simple Blog API
:toc:
:docktype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
:sectlinks:
== 글 단건조회
=== 요청
include::{snippets}/index/http-request.adoc[]
include::{snippets}/post-inquiry/http-request.adoc[]
include::{snippets}/post-inquiry/path-parameters.adoc[]
=== 응답
include::{snippets}/index/http-response.adoc[]
include::{snippets}/post-inquiry/http-response.adoc[]
include::{snippets}/post-inquiry/response-fields.adoc[]
=== curl
include::{snippets}/index/curl-request.adoc[]
include::{snippets}/post-inquiry/curl-request.adoc[]
== 글 작성
=== 요청
include::{snippets}/post-create/http-request.adoc[]
include::{snippets}/post-create/request-fields.adoc[]
=== 응답
include::{snippets}/post-create/http-response.adoc[]
=== curl
include::{snippets}/post-create/curl-request.adoc[]

View File

@@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.10">
<title>Untitled</title>
<title>Simple Blog API</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
@@ -435,39 +435,202 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body class="article">
<body class="article toc2 toc-left">
<div id="header">
<h1>Simple Blog API</h1>
<div class="details">
<span id="revnumber">version 0.0.1-SNAPSHOT</span>
</div>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#_글_단건조회">글 단건조회</a>
<ul class="sectlevel2">
<li><a href="#_요청">요청</a></li>
<li><a href="#_응답">응답</a></li>
<li><a href="#_curl">curl</a></li>
</ul>
</li>
<li><a href="#_글_작성">글 작성</a>
<ul class="sectlevel2">
<li><a href="#_요청_2">요청</a></li>
<li><a href="#_응답_2">응답</a></li>
<li><a href="#_curl_2">curl</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div id="content">
<div class="sect1">
<h2 id="_글_단건조회"><a class="link" href="#_글_단건조회">글 단건조회</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_요청"><a class="link" href="#_요청">요청</a></h3>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">GET /posts/1 HTTP/1.1
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">GET /posts/1 HTTP/1.1
Accept: application/json
Host: localhost:8080</code></pre>
Host: api.simpleblog.com</code></pre>
</div>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 1. /posts/{postId}</caption>
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Parameter</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>postId</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">게시글 ID</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_응답"><a class="link" href="#_응답">응답</a></h3>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">HTTP/1.1 200 OK
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 44
Content-Length: 72
{"id":1,"title":"제목","content":"내용"}</code></pre>
{"id":1,"title":"글 제목입니다.","content":"글 내용입니다."}</code></pre>
</div>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Path</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>id</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">게시글 ID</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>title</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">제목</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>content</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">내용</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_curl"><a class="link" href="#_curl">curl</a></h3>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">$ curl 'http://localhost:8080/posts/1' -i -X GET \
<pre class="highlightjs highlight"><code data-lang="bash" class="language-bash hljs">$ curl 'https://api.simpleblog.com/posts/1' -i -X GET \
-H 'Accept: application/json'</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_글_작성"><a class="link" href="#_글_작성">글 작성</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_요청_2"><a class="link" href="#_요청_2">요청</a></h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">POST /posts/ HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 65
Host: api.simpleblog.com
{"title":"글 제목입니다.","content":"글 내용입니다."}</code></pre>
</div>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 20%;">
<col style="width: 20%;">
<col style="width: 20%;">
<col style="width: 20%;">
<col style="width: 20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Path</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Optional</th>
<th class="tableblock halign-left valign-top">Constraint</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">title</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">제목</p></td>
<td class="tableblock halign-left valign-top"></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">좋은 제목 입력해주세요.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">content</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">내용</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Y</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_응답_2"><a class="link" href="#_응답_2">응답</a></h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">HTTP/1.1 200 OK</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_curl_2"><a class="link" href="#_curl_2">curl</a></h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="bash" class="language-bash hljs">$ curl 'https://api.simpleblog.com/posts/' -i -X POST \
-H 'Content-Type: application/json;charset=UTF-8' \
-H 'Accept: application/json' \
-d '{"title":"글 제목입니다.","content":"글 내용입니다."}'</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 0.0.1-SNAPSHOT<br>
Last updated 2022-07-30 01:12:38 +0900
Last updated 2022-07-30 06:12:05 +0900
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/styles/github.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/highlight.min.js"></script>
<script>hljs.initHighlighting()</script>
</body>
</html>

View File

@@ -2,44 +2,47 @@ package com.example.simpleblog.controller;
import com.example.simpleblog.domain.Post;
import com.example.simpleblog.repository.PostRepository;
import org.junit.jupiter.api.BeforeEach;
import com.example.simpleblog.request.PostCreate;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.simpleblog.com", uriPort = 443)
@ExtendWith(RestDocumentationExtension.class)
public class PostControllerDocTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private PostRepository postRepository;
@BeforeEach
public void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.build();
}
@Autowired
ObjectMapper objectMapper;
@Test
@DisplayName("글 단건 조회 테스트")
void test() throws Exception {
void get_post() throws Exception {
// given
Post post = Post.builder()
.title("제목")
@@ -54,6 +57,43 @@ public class PostControllerDocTest {
)
.andExpect(status().isOk())
.andDo(print())
.andDo(document("index"));
.andDo(document("post-inquiry",
pathParameters(
parameterWithName("postId").description("게시글 ID")
),
responseFields(
fieldWithPath("id").description("게시글 ID"),
fieldWithPath("title").description("제목"),
fieldWithPath("content").description("내용")
)
));
}
@Test
@DisplayName("글 등록 테스트")
void add_post() throws Exception {
// given
PostCreate request = PostCreate.builder()
.title("글 제목입니다.")
.content("글 내용입니다.")
.build();
String json = objectMapper.writeValueAsString(request);
// expected
this.mockMvc.perform(post("/posts/")
.contentType(APPLICATION_JSON)
.accept(APPLICATION_JSON)
.content(json)
)
.andExpect(status().isOk())
.andDo(print())
.andDo(document("post-create",
requestFields(
fieldWithPath("title").description("제목")
.attributes(key("constraint").value("좋은 제목 입력해주세요.")),
fieldWithPath("content").description("내용").optional()
)
));
}
}

View File

@@ -0,0 +1,12 @@
|===
|Path|Type|Description|Optional|Constraint
{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{#optional}}Y{{/optional}}
|{{#constraint}} {{.}} {{/constraint}}
{{/fields}}
|===