#14 simple blog : spring rest docs custom
This commit is contained in:
@@ -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[]
|
||||
@@ -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>
|
||||
@@ -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()
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
|===
|
||||
|Path|Type|Description|Optional|Constraint
|
||||
|
||||
{{#fields}}
|
||||
|{{path}}
|
||||
|{{type}}
|
||||
|{{description}}
|
||||
|{{#optional}}Y{{/optional}}
|
||||
|{{#constraint}} {{.}} {{/constraint}}
|
||||
|
||||
{{/fields}}
|
||||
|===
|
||||
Reference in New Issue
Block a user