Skip to content

Commit

Permalink
[FEAT] Swagger 적용 (#130)
Browse files Browse the repository at this point in the history
* chore: Swagger 의존성 추가

* config: Swagger 경로 인가로직 제외

* config: Swagger 설정

* feat: 테스트용 로그인 제거

* feat: 인증 API 문서 작성

* feat: 회원 API 문서 작성

* feat: 게시글 API 문서 작성

* feat: 매칭 API 문서 작성

* feat: 댓글 API 문서 작성

* feat: 알림 API 문서 작성

* feat: 채팅방 API 문서 작성

* refactor: 불필요한 필드와 import 구문 제거
  • Loading branch information
Profile-exe authored Sep 5, 2024
1 parent 3170ae3 commit 33d6e4a
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 32 deletions.
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ dependencies {
implementation 'org.springframework.session:spring-session-core'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.session:spring-session-data-redis'

implementation 'org.springframework.boot:spring-boot-starter-validation'

// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

// p6spy 의존성 추가 - SQL 로그 확인
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'

Expand Down
36 changes: 12 additions & 24 deletions src/main/java/econo/buddybridge/auth/controller/AuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import econo.buddybridge.auth.OAuthProvider;
import econo.buddybridge.auth.dto.kakao.KakaoLoginParams;
import econo.buddybridge.auth.service.OAuthLoginService;
import econo.buddybridge.common.annotation.AllowAnonymous;
import econo.buddybridge.member.dto.MemberResDto;
import econo.buddybridge.member.service.MemberService;
import econo.buddybridge.utils.api.ApiResponse;
import econo.buddybridge.utils.api.ApiResponse.CustomBody;
import econo.buddybridge.utils.api.ApiResponseGenerator;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import java.net.URI;
Expand All @@ -17,40 +17,26 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/oauth")
@Tag(name = "인증 API", description = "인증 관련 API")
public class AuthController {

private final OAuthLoginService oAuthLoginService;
private final MemberService memberService;

@Value("${oauth.kakao.url.front-url}")
private String frontUrl;

// 테스트용 로그인 엔드포인트
@GetMapping("/login/{member-id}")
@AllowAnonymous // 추가
public ApiResponse<CustomBody<MemberResDto>> testLogin(
@PathVariable("member-id") Long memberId,
HttpServletRequest request
) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate(); // 세션 정보를 삭제한다
}

session = request.getSession(true); // 새로운 세션을 생성한다

MemberResDto member = memberService.findMemberById(memberId);
session.setAttribute("memberId", member.memberId());

return ApiResponseGenerator.success(member, HttpStatus.OK);
}

@Operation(summary = "로그아웃", description = "세션을 제거합니다.")
@GetMapping("/logout")
public ApiResponse<CustomBody<String>> logout(HttpServletRequest request) {
HttpSession session = request.getSession(false);
Expand All @@ -62,6 +48,7 @@ public ApiResponse<CustomBody<String>> logout(HttpServletRequest request) {
return ApiResponseGenerator.success("이미 로그아웃 상태입니다.", HttpStatus.OK);
}

@Operation(summary = "카카오 소셜 로그인 (코드로 로그인)", description = "Redirect URL이 백엔드 주소로 설정될 때 사용합니다.")
@GetMapping("/login")
public ApiResponse<CustomBody<MemberResDto>> login(@RequestParam("code") String code, HttpServletRequest request) {
KakaoLoginParams params = new KakaoLoginParams(code);
Expand All @@ -78,6 +65,7 @@ public ApiResponse<CustomBody<MemberResDto>> login(@RequestParam("code") String
return ApiResponseGenerator.success(memberDto, httpHeaders, HttpStatus.PERMANENT_REDIRECT);
}

@Operation(summary = "카카오 소셜 로그인 (토큰으로 로그인)", description = "Redirect URL이 프론트엔드 주소로 설정될 때 사용합니다.")
@PostMapping("/login")
public ApiResponse<CustomBody<MemberResDto>> login(@RequestBody KakaoLoginParams params, HttpServletRequest request) {
MemberResDto memberDto = oAuthLoginService.login(params);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import econo.buddybridge.utils.api.ApiResponse.CustomBody;
import econo.buddybridge.utils.api.ApiResponseGenerator;
import econo.buddybridge.utils.session.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -24,10 +26,12 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/comments")
@Tag(name = "댓글 API", description = "댓글 관련 API")
public class CommentController {

private final CommentService commentService;

@Operation(summary = "댓글 조회", description = "게시글의 댓글을 조회합니다.")
@GetMapping("/{post-id}")
@AllowAnonymous
public ApiResponse<CustomBody<CommentCustomPage>> getComments(
Expand All @@ -40,6 +44,7 @@ public ApiResponse<CustomBody<CommentCustomPage>> getComments(
return ApiResponseGenerator.success(comments, HttpStatus.OK);
}

@Operation(summary = "댓글 생성", description = "게시글에 댓글을 생성합니다.")
@PostMapping("/{post-id}")
public ApiResponse<CustomBody<Long>> createComment(
@PathVariable("post-id") Long postId,
Expand All @@ -51,6 +56,7 @@ public ApiResponse<CustomBody<Long>> createComment(
return ApiResponseGenerator.success(createdCommentId, HttpStatus.CREATED);
}

@Operation(summary = "댓글 수정", description = "댓글을 수정합니다.")
@PutMapping("/{comment-id}")
public ApiResponse<CustomBody<Long>> updateComment(
@PathVariable("comment-id") Long commentId,
Expand All @@ -62,6 +68,7 @@ public ApiResponse<CustomBody<Long>> updateComment(
return ApiResponseGenerator.success(updatedCommentId, HttpStatus.OK);
}

@Operation(summary = "댓글 삭제", description = "댓글을 삭제합니다.")
@DeleteMapping("/{comment-id}")
public ApiResponse<CustomBody<Void>> deleteComment(
@PathVariable("comment-id") Long commentId,
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/econo/buddybridge/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package econo.buddybridge.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {

@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.info(new Info()
.title("Buddy Bridge API")
.description("Buddy Bridge API 명세서")
.version("1.0.0"));
}
}
13 changes: 10 additions & 3 deletions src/main/java/econo/buddybridge/config/WebConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) { // CORS 설정
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedOriginPatterns(
"http://localhost:3000", "https://localhost:3000",
"http://localhost:8080", "https://localhost:8080",
"http://localhost:8081", "https://localhost:8081",
"https://buddybridge-git-master-simminbos-projects.vercel.app/"
)
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true);
Expand All @@ -27,8 +32,10 @@ public void addInterceptors(InterceptorRegistry registry) {
.addPathPatterns("/**")
.excludePathPatterns(
"/api/oauth/login",
"/api/oauth/login/**",
"/api/oauth/logout"
"/api/oauth/logout",
"/swagger-ui/**",
"/swagger-resources/**",
"/v3/api-docs/**"
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import econo.buddybridge.utils.api.ApiResponse;
import econo.buddybridge.utils.api.ApiResponseGenerator;
import econo.buddybridge.utils.session.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -14,10 +16,12 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/matching")
@Tag(name = "매칭 API", description = "매칭 관련 API")
public class MatchingController {

private final MatchingService matchingService;

@Operation(summary = "매칭 생성(수락)", description = "매칭을 생성(수락)합니다.")
@PostMapping("/accept")
public ApiResponse<ApiResponse.CustomBody<Long>> createMatching(
@RequestBody MatchingReqDto matchingReqDto,
Expand All @@ -29,6 +33,7 @@ public ApiResponse<ApiResponse.CustomBody<Long>> createMatching(
}

// matching 완료 -> DONE 변경, 거절 -> FAILED 변경
@Operation(summary = "매칭 상태 변경", description = "매칭 상태를 변경합니다. 매칭 상태(DONE, FAILED, PENDING)에 따라 게시글 상태도 변경됩니다.")
@PutMapping("/{matching-id}")
public ApiResponse<ApiResponse.CustomBody<Long>> updateMatching(
@PathVariable("matching-id") Long matchingId,
Expand All @@ -42,6 +47,7 @@ public ApiResponse<ApiResponse.CustomBody<Long>> updateMatching(

// matching 완전 삭제 -> 좋은 방법인가
// 실수로 제거한 경우는 채팅방을 다시 만들어야하는지
@Operation(summary = "매칭 삭제", description = "매칭을 삭제합니다.")
@DeleteMapping("/{matching-id}")
public ApiResponse<ApiResponse.CustomBody<Void>> deleteMatching(
@PathVariable("matching-id") Long matchingId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import econo.buddybridge.utils.api.ApiResponse;
import econo.buddybridge.utils.api.ApiResponseGenerator;
import econo.buddybridge.utils.session.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
Expand All @@ -19,13 +21,15 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/chat/matchings")
@Tag(name = "채팅방 API", description = "채팅방 관련 API")
public class MatchingRoomController {

private final MatchingRoomService matchingRoomService;

// 매칭 상태 변경되면 -> 게시글 상태 변경되도록

// 매칭방 목록 조회
// 채팅방 목록 조회
@Operation(summary = "채팅방 목록 조회", description = "채팅방 목록을 조회합니다.")
@GetMapping("")
public ApiResponse<ApiResponse.CustomBody<MatchingCustomPage>> getAllMatchingRooms(
@RequestParam("limit") Integer size,
Expand All @@ -38,7 +42,8 @@ public ApiResponse<ApiResponse.CustomBody<MatchingCustomPage>> getAllMatchingRoo
return ApiResponseGenerator.success(matchings, HttpStatus.OK);
}

// GET 매칭방 상세 조회(대화 내용 조회)
// GET 채팅방 상세 조회(대화 내용 조회)
@Operation(summary = "채팅방 대화 내용 조회", description = "채팅방 대화 내용을 조회합니다.")
@GetMapping("/{matching-id}")
public ApiResponse<ApiResponse.CustomBody<ChatMessageCustomPage>> getChatMessages(
@PathVariable("matching-id") Long matchingId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import econo.buddybridge.utils.api.ApiResponse.CustomBody;
import econo.buddybridge.utils.api.ApiResponseGenerator;
import econo.buddybridge.utils.session.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -19,17 +21,20 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users")
@Tag(name = "회원 API", description = "회원 관련 API")
public class MemberController {

private final MemberService memberService;

@Operation(summary = "회원 정보 조회", description = "회원 정보를 조회합니다.")
@GetMapping("/info")
public ApiResponse<CustomBody<MemberResDto>> findMember(HttpServletRequest request) {
Long memberId = SessionUtils.getMemberId(request);

return ApiResponseGenerator.success(memberService.findMemberById(memberId), HttpStatus.OK);
}

@Operation(summary = "회원 정보 수정", description = "회원 정보를 수정합니다.")
@PutMapping("/info")
public ApiResponse<CustomBody<Void>> updateMember(HttpServletRequest request, @RequestBody MemberReqDto memberReqDto) {
Long memberId = SessionUtils.getMemberId(request);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package econo.buddybridge.notification.controller;

import econo.buddybridge.common.annotation.AllowAnonymous;
import econo.buddybridge.notification.service.EmitterService;
import econo.buddybridge.utils.session.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
Expand All @@ -16,12 +17,13 @@
@RestController
@RequestMapping("/api/sse")
@RequiredArgsConstructor
@Tag(name = "알림 API")
public class EmitterController {

private final EmitterService emitterService;

@Operation(summary = "알림 연결", description = "SSE로 알림을 연결합니다.")
@GetMapping(value = "/connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@AllowAnonymous
public SseEmitter connect(
@RequestHeader(value = "Last-Event-ID", required = false, defaultValue = "")
String lastEventId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import econo.buddybridge.utils.api.ApiResponse.CustomBody;
import econo.buddybridge.utils.api.ApiResponseGenerator;
import econo.buddybridge.utils.session.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -19,10 +21,12 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/notifications")
@Tag(name = "알림 API", description = "알림 관련 API")
public class NotificationController {

private final NotificationService notificationService;

@Operation(summary = "알림 조회", description = "알림을 조회합니다.")
@GetMapping
public ApiResponse<CustomBody<NotificationCustomPage>> getNotifications(
@RequestParam("limit") Integer size,
Expand All @@ -34,6 +38,7 @@ public ApiResponse<CustomBody<NotificationCustomPage>> getNotifications(
return ApiResponseGenerator.success(notifications, HttpStatus.OK);
}

@Operation(summary = "알림 읽음 처리", description = "알림을 읽음 처리합니다.")
@PatchMapping("/{notification-id}/read")
public ApiResponse<CustomBody<Void>> markAsRead(
@PathVariable("notification-id") Long notificationId,
Expand Down
Loading

0 comments on commit 33d6e4a

Please sign in to comment.