plugins {
id 'java'
id 'org.springframework.boot' version '3.4.3'
id 'io.spring.dependency-management' version '1.1.7'
id 'com.epages.restdocs-api-spec' version '0.19.4' // ✅ OpenAPI spec 생성용
}
dependencies {
// ✅ REST Docs
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
// ✅ OpenAPI 3 스펙 변환 라이브러리
testImplementation 'com.epages:restdocs-api-spec-mockmvc:0.19.4'
}
openapi3 {
servers = [
{ url = 'http://localhost:8080' }
]
title = 'Boilerplate API'
description = 'Boilerplate API description'
version = '1.0.0'
format = 'json'
outputFileNamePrefix = 'openapi3'
outputDirectory = file("build/api-spec") // 🔹 openapi3.json 생성 위치
}
의존성 추가
✅ 실제 적용 코드
@AutoConfigureRestDocs(outputDir = "build/generated-snippets") // ✅ 추가
@WebMvcTest(JoinController.class)
@DisplayName("유저 회원가입 Controller")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@AutoConfigureMockMvc(addFilters = false)
class JoinControllerTest {
@MockitoBean
private JoinService joinService;
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
private Long id = 1L;
private String email = "email@email.com";
private String username = "email";
private String password = "password";
@Nested
class 회원가입_성공 {
@Test
void 회원가입_성공_정상_회원가입() throws Exception {
// given
JoinRequest request = new JoinRequest(email, password);
JoinResponse response = JoinResponse.builder()
.id(id)
.username(username)
.build();
given(joinService.join(any(JoinRequest.class))).willReturn(response);
// when & then
mockMvc.perform(post("/api/join")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").value(id))
.andExpect(jsonPath("$.username").value(username))
.andDo(document("join-success", // ✅ 스니펫 이름
resource(
ResourceSnippetParameters.builder()
.tag("회원가입")
.summary("회원가입 API")
.description("회원가입 후 사용자 ID와 이름을 반환")
.requestFields(
fieldWithPath("email").description("이메일"),
fieldWithPath("password").description("비밀번호")
)
.responseFields(
fieldWithPath("id").description("유저 ID"),
fieldWithPath("username").description("사용자 이름")
)
.requestSchema(schema("JoinRequest"))
.responseSchema(schema("JoinResponse"))
.build()
)
));
}
}
}
document 의존성 변경
import static com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper.document;
테스트 실행으로 OpenAPI 스펙 생성
./gradlew clean test openapi3
openapi3.json 명세 파일 src/main/resources/static/docs로 복사
mkdir -p src/main/resources/static/docs
cp build/api-spec/openapi3.json src/main/resources/static/docs/openapi3.json
도커 실행
docker rm -f swagger-ui # 기존 컨테이너 제거 (optional)
docker run -d -p 8081:8080 `
-e "SWAGGER_JSON=/tmp/openapi3.json" `
-v "$PWD\src\main\resources\static\docs:/tmp" `
--name swagger-ui `
swaggerapi/swagger-ui
자동화 스크립트 ps1
# run-swagger.ps1
Write-Host "📦 Running tests and generating OpenAPI spec..."
./gradlew.bat clean test openapi3
if (!(Test-Path -Path "build\api-spec\openapi3.json")) {
Write-Host "❌ openapi3.json not found! Check your REST Docs generation."
exit 1
}
Write-Host "📄 Copying OpenAPI spec to static docs folder..."
New-Item -ItemType Directory -Force -Path "src\main\resources\static\docs" | Out-Null
Copy-Item "build\api-spec\openapi3.json" "src\main\resources\static\docs\openapi3.json" -Force
Write-Host "🧼 Cleaning up old Swagger UI container (if exists)..."
docker rm -f swagger-ui | Out-Null
Write-Host "🚀 Starting Swagger UI on http://localhost:8081"
$swaggerJsonPath = "$PWD\src\main\resources\static\docs"
docker run -d -p 8081:8080 `
-e "SWAGGER_JSON=/tmp/openapi3.json" `
-v "${swaggerJsonPath}:/tmp" `
--name swagger-ui `
swaggerapi/swagger-ui
Write-Host "✅ Swagger UI is now available at: http://localhost:8081"
'Project > Boilerplate' 카테고리의 다른 글
로컬 개발에서 배포, 개발 환경 분리하기 (0) | 2025.04.10 |
---|---|
Mock 테스트 중 엔티티 id 및 SecurityContextHolder 설정 (0) | 2025.04.02 |
WebMvcTest + Spring REST doc 적용 ( 1 / 2 - MockMvc ) (0) | 2025.03.28 |
필터 예외 처리 (0) | 2025.03.17 |
API 예외 처리 (0) | 2025.03.17 |