์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- ํ๊ณ
- HTML
- CSS
- ์๋ฐ
- ๊นํ๋ธ
- Spring Data JDBC
- ์ปฌ๋ ์ ํ๋ ์์ํฌ
- ์๋ฃ๊ตฌ์กฐ
- ์ธํ ๋ฆฌ์ ์ด
- Spring Security
- ๋ฐฑ์๋
- ๋ฐฑ์ค์๊ณ ๋ฆฌ์ฆ
- ๋ฌธ์์ด๋ค์ง๊ธฐ
- ์ฒซ๊ธ์๋๋ฌธ์
- ์คํ๋ง
- fibonacci
- ์๊ณ ๋ฆฌ์ฆ
- ๊ณ์ฐ๊ธฐ๋ง๋ค๊ธฐ
- java
- ์ ๋ค๋ฆญ์ค
- ๊ฑฐ๋ญ์ ๊ณฑ
- ๊ทธ๋ฆฌ๋
- spring data jpa
- CLI๋ช ๋ น์ด
- ๋ฐ์ผ๋ฆฌ์ฝ๋ฉ
- Publishing
- FilterChain
- ๋ถํธ์บ ํ
- ํ์ดํ๋ก๊ทธ๋๋ฐ
- testing
- Today
- Total
๋์ ๋ชจ์
057 | API Documentation, Swagger, SpringRest ๋ณธ๋ฌธ
๐ API Documentation
ํด๋ผ์ด์ธํธ๋ HTTP request URL(๋๋ URI)์ ํตํด ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ค. ์ด ๋ ํด๋ผ์ด์ธํธ๊ฐ REST API ๋ฐฑ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฒญ์ ์ ์กํ๊ธฐ ์ํด์ ์์์ผ ๋๋ ์์ฒญ ์ ๋ณด(์์ฒญ URL(๋๋ URI), request body, query parameter ๋ฑ)๋ฅผ ๋ฌธ์ํ ํ ๊ฒ์ API ๋ฌธ์ ๋๋ API ์คํ(์ฌ์)์ด๋ผ๊ณ ํ๋ค.
API ๋ฌธ์๋ ๊ฐ๋ฐ์๊ฐ ์ง์ ์๊ธฐ๋ก ์์ฑํ ์๋ ์์ง๋ง, ๊ฐ๋ฐ์ค์ด๊ฑฐ๋ ์ ์ง๋ณด์๋ฅผ ํ ๋ API๊ฐ ์์ ๋ ์๋ ์๊ณ , ํด๋ผ์ด์ธํธ์๊ฒ ์ ๊ณต๋ API ์ ๋ณด์ ์๊ธฐ๋ก ์์ฑ๋ API ๋ฌธ์ ์ ๋ณด๊ฐ ๋ค๋ฅผ ์ ์๊ธฐ ๋๋ฌธ์ ๋นํจ์จ์ ์ด๋ค. API ๋ฌธ์ ์๋ํ๋ฅผ ํตํด API์์ ์๊ธฐ๋ ์๋ฌ ๋ฐ์์ ๋ฐฉ์งํ๊ณ ์์ ์๊ฐ์ ๋จ์ถํ ์ ์๋ค.
๐งฉ Swagger์ API ๋ฌธ์ํ ๋ฐฉ์ - ์ ๋ํ ์ด์ ๊ธฐ๋ฐ
-
- ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ ๋ฌธ์ํ๋ฅผ ์ํ ์ ๋ํ ์ด์ ๋ค์ด ํฌํจ๋๋ค.
- ๊ฐ๋ ์ฑ ๋ฐ ์ ์ง ๋ณด์์ฑ์ด ๋จ์ด์ง๋ค.
- API ๋ฌธ์์ API ์ฝ๋ ๊ฐ์ ์ ๋ณด ๋ถ์ผ์น ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค.
- API ํด๋ก์จ์ ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์๋ค.
๐งฉ Spring Rest Docs์ API ๋ฌธ์ํ ๋ฐฉ์ - ํ ์คํธ ์ผ์ด์ค ๊ธฐ๋ฐ
-
- ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ ๋ฌธ์ํ๋ฅผ ์ํ ์ ๋ณด๋ค์ด ํฌํจ๋์ง ์๋๋ค.
- ํ ์คํธ ์ผ์ด์ค์ ์คํ์ด “passed”์ฌ์ผ API ๋ฌธ์๊ฐ ์์ฑ๋๋ค.
- ํ ์คํธ ์ผ์ด์ค๋ฅผ ๋ฐ๋์ ์์ฑํด์ผ๋๋ค.
- API ํด๋ก์จ์ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง ์๋๋ค.
๐ Swagger
- build.gradle > ์์กด์ฑ ์ถ๊ฐ
dependencies{
implementation 'io.springfox:springfox-boot-starter:3.0.0'
}
- NPE ๋ฐ์ > application.yml > ์์ฑ ์ถ๊ฐ
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
- ๋จ์ : @Api~์ ๋ํ ์ด์ ์ ์ปจํธ๋กค๋ฌ์ dtoํด๋์ค์๋ ๊ณ์ ์ถ๊ฐํด์ผํจ → ์ฝ๋ ๋ณต์ก
- ์๋ฒ ์คํ ํ ์๋ url๋ก ์ ์ํ๋ฉด swagger๋ก ๋ง๋ค์ด์ง API ๋ฌธ์๋ฅผ ํ์ธํ ์ ์๋ค.
๐ Spring Rest Docs
Swagger๋ ์ค์ ๊ธฐ๋ฅ ๊ตฌํ ๋ก์ง์ ์ ๋ํ ์ด์ ์ด ์ถ๊ฐ๋์ด ๊ฐ๋ ์ฑ๋ ๋จ์ด์ง๊ณ ๋ถํ์ํ๊ฒ ์ฝ๋๊ฐ ๊ธธ์ด์ง๋ ๋ฌธ์ ์ ์ด ์์๋๋ฐ, Spring Rest Docs๋ ์ฝ๋๊ฐ ์ค์ ๊ธฐ๋ฅ ๋ก์ง์ด ์๋ test์ ์ถ๊ฐํ๋ค. ๊ธฐ๋ฅ ๋ก์ง์ ์๋ํ ์ด์ ์ ์ถ๊ฐํ ํ์๋ ์๊ณ , API๋ฌธ์๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋ ํ ์คํธ๋ ํต๊ณผํด์ผ ๋ง๋ค์ด์ง๊ธฐ ๋๋ฌธ์ ์ค๋ฅ ๋ฐ์ ํ๋ฅ ์ด ์ค์ด๋ ๋ค.
๐งฉ Spring Rest Docs ํ๋ฆ
- ํ
์คํธ ์ฝ๋ ์์ฑ
1-1. ์ฌ๋ผ์ด์ค ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
1-2. API ์คํ ์ ๋ณด ์ฝ๋๋ฅผ ์์ฑํ๋ค. - test task ์คํ
2-1. ์ฌ๋ผ์ด์ค ํ ์คํธ ์ฝ๋ ์คํํ๋ค.
2-2. ์คํ ๊ฒฐ๊ณผ passed: ๋ค์ ์์ ์งํ / failed: ํ ์คํธ ์ผ์ด์ค ์์ ํ passedํ ๋๊น์ง ํ ์คํธ๋ฅผ ์งํํ๋ค. - API ๋ฌธ์ ์ค๋ํ ์์ฑ
3-1. ํ ์คํธ ์ผ์ด์ค ์คํ๊ฒฐ๊ณผ๊ฐ passed์ด๋ฉด ์ฝ๋์ ํฌํจ๋ API ์คํ ์ ๋ณด ์ฝ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก API ๋ฌธ์ ์ค๋ํ์ด .adoc ํ์ฅ์๋ฅผ ๊ฐ์ง ํ์ผ๋ก ์์ฑ๋๋ค. - ์ค๋ํ์ ํฌํจํ API ๋ฌธ์ ์์ฑ
- .adoc ํ์ผ์ API ๋ฌธ์๋ฅผ HTML๋ก ๋ณํ
์์ฑ๋ API ๋ฌธ์๋ฅผ HTML ํ์ผ๋ก ๋ณํํ๋ค.
HTML๋ก ๋ณํ๋ API ๋ฌธ์๋ HTML ํ์ผ ์์ฒด๋ฅผ ๊ณต์ ํ ์๋ ์๊ณ , URL์ ํตํด ํด๋น HTML์ ์ ์ํด์ ํ์ธํ ์ ์๋ค.
๐งฉ Spring Rest Docs ์ค์
plugins {
id 'org.springframework.boot' version '2.7.1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
// ํ์ฅ์ .adoc๋ฅผ ๊ฐ์ง๋ AsciiDoc ๋ฌธ์๋ฅผ ์์ฑํด์ฃผ๋ Asciidoctor ์ฌ์ฉํ๊ธฐ ์ํ ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ
id "org.asciidoctor.jvm.convert" version "3.3.2"
id 'java'
}
// ext ๋ณ์์ set() ๋ฉ์๋๋ก API ๋ฌธ์ ์ค๋ํ ์์ฑ ๊ฒฝ๋ก ์ง์
ext {
set('snippetsDir', file("build/generated-snippets"))
}
// AsciiDoctor์์ ์ฌ์ฉ๋๋ ์์กด ๊ทธ๋ฃน ์ง์
configurations {
asciidoctorExtensions
}
dependencies {
// spring-restdocs-core / spring-restdocs-mockmvc ์์กด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
// spring-restdocs-asciidoctor ์์กด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ
asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
}
// :test task ์คํ ์ API ๋ฌธ์ ์์ฑ ์ค๋ํ ๋๋ ํ ๋ฆฌ ๊ฒฝ๋ก ์ค์
tasks.named('test') {
outputs.dir snippetsDir
useJUnitPlatform()
}
// :asciidoctor task ์คํ ์ asciidoctorExtensions ์ค์
tasks.named('asciidoctor') {
configurations "asciidoctorExtensions"
inputs.dir snippetsDir
dependsOn test
}
// :build task ์คํ ์ ์ ์คํ๋๋ task
task copyDocument(type: Copy) {
dependsOn asciidoctor
from file("build/docs/asciidoc/")
into file("src/main/resources/static/docs")
}
build {
// :copyDocument task ๋จผ์ ์คํ
dependsOn copyDocument
}
// :bootJar task๋ ์ดํ๋ฆฌ์ผ์ด์
์คํ ํ์ผ์ ์์ฑ
bootJar {
enabled = true
dependsOn copyDocument // :bootJar task์คํ ์ ์ :copyDocument task๊ฐ ์คํ
from ("${asciidoctor.outputDir}/html5") {
into 'static/docs'
}
}
๐งฉ Spring Rest Docs ํ ์คํธ ์ผ์ด์ค
@EnableJpaAuditing
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@EnableJpaAuditing์ Application ํด๋์ค์ ์ถ๊ฐํ๊ฒ ๋๋ฉด JPA ๊ด๋ จ Bean์ ํ์๋ก ํ๊ธฐ ๋๋ฌธ์ @WebMvcTest ์ ๋ํ ์ด์ ์ ์ฌ์ฉํด์ ํ ์คํธ๋ฅผ ์งํ ํ ๋ @MockBean(JpaMetamodelMappingContext.class)๋ฅผ Mock ๊ฐ์ฒด๋ก ์ฃผ์ ํด์ผ ํ๋ค.
@WebMvcTest(MemberController.class)
@MockBean(JpaMetamodelMappingContext.class)
@AutoConfigureRestDocs
public class MemberControllerRestDocsTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private Service service;
@MockBean
private Mapper mapper;
@Autowired
private Gson gson;
@Test
public void rest() throws Exception {
// given
Dto dto = new Dto("cheese@cat.com", "cheese", "010-1212-1212");
String content = gson.toJson(dto);
Response response = new Response(
1L,
"cheese@cat.com",
"cheese",
"010-1212-1212",
new Stamp());
given(mapper.Mocking1(Mockito.any(Dto.class))).willReturn(new Entity());
given(service.Mocking2(Mockito.any(Entity.class))).willReturn(new Entity());
given(mapper.Mocking3(Mockito.any(Entity.class))).willReturn(response);
// when
ResultActions actions =
mockMvc.perform(
post("uri")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);
// then
actions
.andExpect(status().isCreated())
.andExpect(jsonPath("$.data.field").value(post.getField()))
.andDo(document(
"identifier",
getRequestPreProcessor(),
ApiDocumentUtils.getResponsePreProcessor(),
requestFields(
List.of(
fieldWithPath("field1").type(JsonFieldType.STRING).description("field1"),
fieldWithPath("field2").type(JsonFieldType.STRING).description("field2")
)
),
responseFields(
List.of(
fieldWithPath("field1").type(JsonFieldType.OBJECT).description("field1"),
fieldWithPath("field2").type(JsonFieldType.NUMBER).description("field2")
)
)
));
}
}
public interface ApiDocumentUtils {
static OperationRequestPreprocessor getRequestPreProcessor() {
return preprocessRequest(prettyPrint());
}
static OperationResponsePreprocessor getResponsePreProcessor() {
return preprocessResponse(prettyPrint());
}
}
ํ ์คํธ๊ฐ ํต๊ณผํ๋ฉด build/generated-snippets/์ค๋ํ ์๋ณ์ ๊ฒฝ๋ก์ .adoc API ๋ฌธ์๋ค์ด ์์ฑ๋๋ค.
๐งฉ ์ค๋ํ์ ์ด์ฉํ API ๋ฌธ์ํ
๋ง๋ API ๋ฌธ์๋ ์ค๋ํ(์กฐ๊ฐ ๋ชจ์)์ด๊ธฐ ๋๋ฌธ์ ์ด ์กฐ๊ฐ์ ํ๋๋ก ๋ชจ์ ํ ํ๋ฆฟ ๋ฌธ์๊ฐ ํ์ํ๋ค.
1. gradle ํ๋ก์ ํธ์์ ํ ํ๋ฆฟ ๋ฌธ์ ๊ธฐ๋ณธ ๊ฒฝ๋ก์ธ src/docs/asciidoc์ index.adoc ํ์ผ์ ์์ฑํ๊ณ ํ ํ๋ฆฟ ๋ฌธ์๋ฅผ ์์ฑํ๋ค.
= template documentation name
:sectnums:
:toc: left
:toclevels: 4
:toc-title: Table of Contents
:source-highlighter: prettify
writer <email>
version, date
***
== controller
=== handler method
.curl-request
include::{snippets}/identifier/curl-request.adoc[]
.http-request
include::{snippets}/identifier/http-request.adoc[]
.request-fields
include::{snippets}/identifier/request-fields.adoc[]
.http-response
include::{snippets}/identifier/http-response.adoc[]
.response-fields
include::{snippets}/identifier/response-fiedls.adoc[]
2. Gradle > Tasks > build > bootJar ๋๋ build๋ก ๋น๋ํ๋ค.
src/main/resource/static/docs ๋๋ ํ ๋ฆฌ์ index.htmlํ์ผ์ด ์์ฑ๋๋ค.
3. html ํ์ผ ํ์ธ
http://localhost:8080/docs/index.html
โ Ref.
https://swagger.io/docs/specification/about/
About Swagger Specification | Documentation | Swagger
What Is OpenAPI? OpenAPI Specification (formerly Swagger Specification) is an API description format for REST APIs. An OpenAPI file allows you to describe your entire API, including: Available endpoints (/users) and operations on each endpoint (GET /users,
swagger.io
OpenAPI 3 Library for spring-boot
Library for OpenAPI 3 with spring boot projects. Is based on swagger-ui, to display the OpenAPI description.Generates automatically the OpenAPI file.
springdoc.org
'SEB > TIL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
061 | ์ธ์ฆ๋ณด์ ๊ธฐ์ด (0) | 2022.09.20 |
---|---|
058 | Asciidocs, Asciidoctor (2) | 2022.09.15 |
052 | Transaction (0) | 2022.09.05 |
046 | Spring Data JDBC (0) | 2022.08.26 |
045 | Checked / Unchecked / Customised Exception (0) | 2022.08.25 |