이번에는 저번 시간까지 만들었던 로그인 API에 대한 문서를 만들어 보겠습니다. Swagger를 활용해서 API문서를 만들어볼건데요, Swagger에 대한 내용은 다음 포스팅을 읽어봐주세요.
https://coding-kim.tistory.com/37
[Spring] Swagger에 대해서 알아보자
Swagger는 RESTful API 문서화를 위한 도구로, API의 사용 방법과 API의 매개변수, 반환값 등을 문서로 정리해주는 역할을 합니다. 이번 글에서는 Spring Framework에서 Swagger를 사용하는 방법을 소개하겠습
coding-kim.tistory.com
Swagger 추가
Swagger를 사용하기 위해 build.gradle에 의존성을 추가하겠습니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'io.springfox:springfox-boot-starter:3.0.0' //<- 추가
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'io.jsonwebtoken:jjwt:0.9.1'
}
Swagger 설정
SwaggerConfig.java
@Import(BeanValidatorPluginsConfiguration.class) //Bean Validation 라이브러리를 사용하여 데이터 유요성 검사 수행하기 위한 구성 제공
@Configuration
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("farm.board.controller")) //package에 있는 모든 클래스를 문서화 대상으로 설정
.paths(PathSelectors.any()) // 모든 api 엔드포인트를 문서화 대상으로 포함
.build()
.securitySchemes(List.of(apiKey())) //api 보안 스키마 설정
.securityContexts(List.of(securityContext())); //
}
private ApiInfo apiInfo() { //API 문서의 메타데이터 설정
return new ApiInfoBuilder()
.title("Spring Kim Board")
.description("Spring board REST API Documentation")
.license("jaeyeon423@gmail.com")
.licenseUrl("https://github.com/jaeyeon423")
.version("1.0")
.build();
}
private static ApiKey apiKey() {
return new ApiKey("Authorization", "Bearer Token", "header");
}
private SecurityContext securityContext() {
return SecurityContext.builder().securityReferences(defaultAuth())
.operationSelector(oc -> oc.requestMappingPattern().startsWith("/api/")).build();
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "global access");
return List.of(new SecurityReference("Authorization", new AuthorizationScope[] {authorizationScope}));
}
}
위 코드에 대해서 설명 드리겠습니다.
- @Import(BeanValidatorPluginsConfiguration.class): Bean Validation 라이브러리를 사용하여 데이터 유효성 검사 수행하기 위한 구성을 제공하는 클래스를 import합니다.
- new Docket(DocumentationType.OAS_30): OpenAPI 3.0 버전을 사용하여 API 문서를 생성합니다.
- apiInfo(apiInfo()): API 문서의 메타데이터를 설정하기 위해 apiInfo() 메소드를 호출합니다.
- select(): API 문서 생성 대상을 설정합니다.
- apis(RequestHandlerSelectors.basePackage("farm.board.controller")): farm.board.controller 패키지에 있는 모든 클래스를 문서화 대상으로 설정합니다.
- paths(PathSelectors.any()): 모든 API 엔드포인트를 문서화 대상으로 포함합니다.
- .securitySchemes(List.of(apiKey())): API 보안 스키마를 설정합니다.
- .securityContexts(List.of(securityContext())): 보안 컨텍스트를 설정합니다.
WebConfig.java
특별한 기능이 없는 클래스이지만 Swagger를 사용하기 위해서 @EnableWebMvc를 추가해줘야합니다.
@EnableWebMvc
@Configuration
public class WebConfig {
}
SecurityConfig.java
Swagger가 생성한 API 문서를 사용하기 위해서 URL 접근 설정을 SecurityConfig에서 해줍니다.
@Override
public void configure(WebSecurity web) throws Exception {
//web.ignoring().mvcMatchers("/exception/**"); // /exception/** 패턴의 요청은 보안 검사를 거치지 않는다
web.ignoring().mvcMatchers("/exception/**","/swagger-ui/**", "/swagger-resources/**", "/v3/api-docs/**"); // /exception/** 패턴의 요청은 보안 검사를 거치지 않는다
}
API 문서 작성
이제 API 문서를 작성해 보겠습니다.
SignController
@Api(value = "Sign Controller", tags = "Sign") // SignController API를 대표하는 value와 tage 정보 설정
@RestController // @Controller + @ResponseBody
@RequiredArgsConstructor // 클래스에서 선언된 final 필드를 가지고 생성자를 만들어줌
public class SignController {
private final SignService signService;
@ApiOperation(value = "회원가입", notes = "회원가입을 한다.") //API 문서에서 aPI의 이름(value)와 설명(notes)를 설정
@PostMapping("/api/sign-up") //HTTP POST 요청을 처리하는 핸들러 메소드를 지정
@ResponseStatus(HttpStatus.CREATED) //메소드의 실행 결과에 대한 HTTP 응답 코드를 HpptStatus.CREATED로 설정
public Response signUp(@Valid @RequestBody SignUpRequest req){ //@Valid : SignUpRequest 객체에 대한 유효성 검사, @RequestBody : 청 바디에서 데이터를 추출하여, 매개변수로 전달된 객체에 매핑
signService.signUp(req); // 회원 가입 처리
return success();
}
@ApiOperation(value = "로그인", notes = "로그인을 한다.")
@PostMapping("/api/sign-in")
@ResponseStatus(HttpStatus.OK)//메소드의 실행 결과에 대한 HTTP 응답 코드를 HpptStatus.OK로 설정
public Response signIn(@Valid @RequestBody SignInRequest req) {
return success(signService.signIn(req)); // 로그인 처리
}
@ApiOperation(value = "토큰 재발급", notes = "리프레시 토큰으로 새로운 액세스 토큰을 발급 받는다.")
@PostMapping("/api/refresh-token")
@ResponseStatus(HttpStatus.OK)
public Response refreshToken(@RequestHeader(value = "Authorization") String refreshToken) {
return success(signService.refreshToken(refreshToken));
}
}
- @Api(value = "Sign Controller", tags = "Sign"): Swagger API 문서에서 Sign Controller API를 대표하는 value와 tag 정보를 설정합니다. value는 API의 분류를 나타내며, tags는 API의 그룹화를 나타냅니다.
- @ApiOperation(value = "회원가입", notes = "회원가입을 한다."): Swagger API 문서에서 API의 value와 notes 정보를 설정합니다. value는 API의 이름을 나타내며, notes는 API의 설명을 나타냅니다.
SignUpRequest.java
@ApiModel(value = "회원가입 요청")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SignUpRequest {
@ApiModelProperty(value = "이메일", notes = "이메일을 입력해주세요", required = true, example = "member@email.com")
@Email(message = "이메일 형식을 맞춰주세요.")
@NotBlank(message = "이메일을 입력해주세요.")
private String email; // 1
@ApiModelProperty(value = "비밀번호", notes = "사용자의 비밀번호를 입력해주세요.", required = true, example = "123456a!")
@NotBlank(message = "비밀번호를 입력해주세요.")
@Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%*#?&])[A-Za-z\\d@$!%*#?&]{8,}$",
message = "비밀번호는 최소 8자리이면서 1개 이상의 알파벳, 숫자, 특수문자를 포함해야합니다.")
private String password; // 2
@NotBlank(message = "사용자 이름을 입력해주세요.")
@Size(min=2, message = "사용자 이름이 너무 짧습니다.")
@Pattern(regexp = "^[A-Za-z가-힣]+$", message = "사용자 이름은 한글 또는 알파벳만 입력해주세요.")
private String username; // 3
@NotBlank(message = "닉네임을 입력해주세요.")
@Size(min=2, message = "닉네임이 너무 짧습니다.")
@Pattern(regexp = "^[A-Za-z가-힣]+$", message = "닉네임은 한글 또는 알파벳만 입력해주세요.")
private String nickname; // 4
public static Member toEntity(SignUpRequest req, Role role, PasswordEncoder encoder){
return new Member(req.email, encoder.encode(req.password), req.username, req.nickname, List.of(role));
}
}
- @ApiModel(value = "회원가입 요청"): \API 문서에서 회원가입 요청에 대한 정보를 제공하는 모델 클래스임을 나타냅니다.
- @ApiModelProperty(value = "이메일", notes = "이메일을 입력해주세요", required = true, example = "member@email.com"): API 문서에서 모델 클래스의 필드 정보를 설정합니다. value는 필드의 이름을 나타내며, notes는 필드의 설명을 나타냅니다. required는 필드의 필수 여부를 나타내며, example은 필드의 예시 값을 나타냅니다.
SignInRequest.java
@ApiModel(value = "로그인 요청")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SignInRequest {
@ApiModelProperty(value = "이메일", notes = "사용자의 이메일을 입력해주세요", required = true, example = "member@email.com")
@Email(message = "이메일 형식을 맞춰주세요.")
@NotBlank(message = "이메일을 입력해주세요.")
private String email; // 1
@ApiModelProperty(value = "비밀번호", notes = "사용자의 비밀번호를 입력해주세요.", required = true, example = "123456a!")
@NotBlank(message = "비밀번호를 입력해주세요.")
private String password; // 2
}
MemberController.java
@Api(value = "Member Controller", tags = "Member")
@RestController
@RequiredArgsConstructor
@Slf4j
public class MemberController {
private final MemberService memberService;
@ApiOperation(value = "사용자 정보 조회", notes = "사용자 정보를 조회한다.")
@GetMapping("/api/members/{id}")
@ResponseStatus(HttpStatus.OK)
public Response read(@PathVariable Long id){
return Response.success(memberService.read(id)); //회원 조회 후 테이터와 함께 성공 반환
}
@ApiOperation(value = "사용자 정보 삭제", notes = "사용자 정보를 삭제한다.")
@DeleteMapping("/api/members/{id}")
@ResponseStatus(HttpStatus.OK)
public Response delete(@PathVariable Long id) {
memberService.delete(id); //회원 삭제
return Response.success(); //성공 반환
}
}
API 문서 확인
먼저 문서를 확인하기 위해 API 문서 url로 이동 하겠습니다. url : http://localhost:8080/swagger-ui/index.html
접속하면 다음과 같은 화면이 보입니다.
코드에서 설정했던 정보들을 문서에서 확인할 수 있습니다.
회원가입
회원가입을 살펴보면 다음과 같이 코드에서 설정해놓은 제약 조건과 예시 데이터를 확인할 수 있습니다.
실제로 테스트를 진행해 보고 싶으면 우측에 Try it out 버튼을 누르면 예시데이터가 입력되어있고 Excute를 눌러 실행해볼 수 있습니다.
로그인
토큰 재발급
로그인 했을 때 받은 refresh token 값을 입력하면
회원 조회
회원 조회까지 모두 정상적으로 결과가 나오는 것을 확인할 수 있었습니다.
궁금한신점이나 잘못된 부분이 있으면 자유롭게 댓글 달아주세요.
'spring > 게시판 api' 카테고리의 다른 글
Spring boot 게시판 API 서버 제작 (14) - 게시판 - 카테고리 - 2 (0) | 2023.02.25 |
---|---|
Spring boot 게시판 API 서버 제작 (13) - 게시판 - 카테고리 (0) | 2023.02.24 |
Spring boot 게시판 API 서버 제작 (11) - 로그인 - Token 코드 리팩토링 (0) | 2023.02.23 |
Spring boot 게시판 API 서버 제작 (11) - 로그인 - 인증 refresh token으로 access token발급 (0) | 2023.02.22 |
Spring boot 게시판 API 서버 제작 (10) - 로그인 - 인증 로직 테스트 (0) | 2023.02.21 |