Skip to content

Commit

Permalink
Configure Open Api to display proper response codes in Swagger UI
Browse files Browse the repository at this point in the history
  • Loading branch information
mertkaanguzel committed Jan 15, 2024
1 parent aba81f3 commit 36bc7d9
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import dev.mertkaanguzel.mediumclone.dto.UpdateArticleDto;
import dev.mertkaanguzel.mediumclone.model.Article;
import dev.mertkaanguzel.mediumclone.service.ArticleService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
Expand All @@ -24,19 +26,34 @@ public ArticleController(ArticleService articleService) {

@PostMapping
@SecurityRequirement(name = "mediumapi")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
@ApiResponse(responseCode = "409", description = "Conflict"),
})
public ResponseEntity<ArticleDto> createArticle(@Valid @RequestBody CreateArticleDto createArticleDto,
Principal principal) {
return ResponseEntity.ok(articleService.createArticle(createArticleDto, principal.getName()));
}

@GetMapping("/{slug}")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public ResponseEntity<ArticleDto> getArticleBySlug(@PathVariable String slug, Principal principal) {
if (principal == null) return ResponseEntity.ok(articleService.getArticleBySlug(slug));

return ResponseEntity.ok(articleService.getArticleBySlug(slug, principal.getName()));
}

@GetMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
})
public ResponseEntity<List<ArticleDto>> getArticles(@RequestParam(value = "tag", required = false) String tag,
@RequestParam(value = "author", required = false) String author,
@RequestParam(value = "favorited", required = false) String favoritedBy,
Expand All @@ -52,6 +69,11 @@ public ResponseEntity<List<ArticleDto>> getArticles(@RequestParam(value = "tag",

@GetMapping("/feed")
@SecurityRequirement(name = "mediumapi")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
})
public ResponseEntity<List<ArticleDto>> getArticlesFeed(@RequestParam(value = "limit", required = false, defaultValue = "20") Integer limit,
@RequestParam(value = "offset", required = false, defaultValue = "0") Integer offset,
Principal principal) {
Expand All @@ -61,6 +83,13 @@ public ResponseEntity<List<ArticleDto>> getArticlesFeed(@RequestParam(value = "l

@PutMapping("/{slug}")
@SecurityRequirement(name = "mediumapi")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Forbidden"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public ResponseEntity<ArticleDto> updateArticle(@PathVariable String slug,
@Valid @RequestBody UpdateArticleDto updateArticleDto,
Principal principal) {
Expand All @@ -70,6 +99,12 @@ public ResponseEntity<ArticleDto> updateArticle(@PathVariable String slug,

@DeleteMapping("/{slug}")
@SecurityRequirement(name = "mediumapi")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Forbidden"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public void deleteArticle(@PathVariable String slug) {
Article article = articleService.findArticleBySlug(slug);
articleService.deleteArticle(article);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import dev.mertkaanguzel.mediumclone.model.UserAccount;
import dev.mertkaanguzel.mediumclone.service.AuthService;
import dev.mertkaanguzel.mediumclone.service.UserService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
Expand All @@ -30,6 +32,11 @@ public AuthController(UserService userService, AuthService authService, Authenti
}

@PostMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
@ApiResponse(responseCode = "409", description = "Conflict"),
})
public ResponseEntity<UserDto> register(@Valid @RequestBody CreateUserDto createUserDto) {
UserAccount user = userService.createUser(createUserDto);
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(createUserDto.email(), createUserDto.password()));
Expand All @@ -38,6 +45,11 @@ public ResponseEntity<UserDto> register(@Valid @RequestBody CreateUserDto create
}

@PostMapping("/login")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public ResponseEntity<UserDto> login(@Valid @RequestBody LoginDto loginDto) {
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginDto.email(), loginDto.password()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import dev.mertkaanguzel.mediumclone.dto.CreateCommentDto;
import dev.mertkaanguzel.mediumclone.model.Comment;
import dev.mertkaanguzel.mediumclone.service.CommentService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
Expand All @@ -23,18 +25,33 @@ public CommentController(CommentService commentService) {
}

@PostMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
})
public ResponseEntity<CommentDto> addComment(@PathVariable String slug,
@Valid @RequestBody CreateCommentDto createCommentDto,
Principal principal) {
return ResponseEntity.ok(commentService.createComment(createCommentDto, slug, principal.getName()));
}

@GetMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
})
public ResponseEntity<List<CommentDto>> getComments(@PathVariable String slug, Principal principal) {
return ResponseEntity.ok(commentService.getComments(slug, principal.getName()));
}

@DeleteMapping("/{id}")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Forbidden"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public void deleteComment(@PathVariable String slug, @PathVariable String id) {
Comment comment = commentService.findComment(slug, id);
commentService.deleteComment(comment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import dev.mertkaanguzel.mediumclone.dto.ArticleDto;
import dev.mertkaanguzel.mediumclone.service.ArticleService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -20,11 +22,21 @@ public FavoriteController(ArticleService articleService) {
}

@PostMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public ResponseEntity<ArticleDto> favorite(@PathVariable String slug, Principal principal) {
return ResponseEntity.ok(articleService.addFavorite(slug, principal.getName()));
}

@DeleteMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public void unfavorite(@PathVariable String slug, Principal principal) {
articleService.removeFavorite(slug, principal.getName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import dev.mertkaanguzel.mediumclone.dto.ProfileDto;
import dev.mertkaanguzel.mediumclone.dto.UserDto;
import dev.mertkaanguzel.mediumclone.service.UserService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
Expand All @@ -23,16 +25,31 @@ public ProfileController(UserService userService) {
}

@GetMapping("/{username}")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public ResponseEntity<ProfileDto> getProfile(@PathVariable String username, Principal principal) {
return ResponseEntity.ok(ProfileDto.fromUserAccount(userService.findUserByName(username), principal.getName()));
}

@PostMapping("/{username}/follow")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public ResponseEntity<ProfileDto> followProfile(@PathVariable String username, Principal principal) {
return ResponseEntity.ok(ProfileDto.fromUserAccount(userService.addFollower(username, principal.getName()), principal.getName()));
}

@DeleteMapping("/{username}/follow")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Not Found"),
})
public ResponseEntity<ProfileDto> unfollowProfile(@PathVariable String username, Principal principal) {
return ResponseEntity.ok(ProfileDto.fromUserAccount(userService.deleteFollower(username, principal.getName()), principal.getName()));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package dev.mertkaanguzel.mediumclone.controller;

import dev.mertkaanguzel.mediumclone.service.TagService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -18,6 +20,9 @@ public TagController(TagService tagService) {
}

@GetMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
})
public ResponseEntity<List<String>> getTags() {
return ResponseEntity.ok(tagService.getTags());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import dev.mertkaanguzel.mediumclone.dto.UserDto;
import dev.mertkaanguzel.mediumclone.service.AuthService;
import dev.mertkaanguzel.mediumclone.service.UserService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
Expand All @@ -27,13 +29,22 @@ public UserController(UserService userService, AuthService authService, Clock cl
}

@GetMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
})
public ResponseEntity<UserDto> getUser(Principal principal) {
return ResponseEntity.ok(UserDto.fromUserAccount(userService.findUserByName(principal.getName()),
authService.getToken()));
}

//??? @PreAuthorize("#entity.username == authentication.name") //?????
@PutMapping
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "422", description = "Unprocessable Content"),
})
public ResponseEntity<UserDto> updateUser(@Valid @RequestBody UpdateUserDto updateUserDto, Principal principal) {
return ResponseEntity.ok(UserDto.fromUserAccount(userService.updateUser(updateUserDto, principal.getName()),
authService.getToken()));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package dev.mertkaanguzel.mediumclone.exception;


import dev.mertkaanguzel.mediumclone.model.UserAccount;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springframework.validation.FieldError;
Expand Down Expand Up @@ -62,4 +68,23 @@ public ResponseEntity<?> userAlreadyExistsExceptionHandler(UserAlreadyExistsExce
public ResponseEntity<?> articleAlreadyExistsExceptionHandler(ArticleAlreadyExistsException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.CONFLICT);
}
/*
@ExceptionHandler(AuthenticationException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ResponseEntity<?> AuthenticationFailureHandler(AuthenticationException exception,
@NotNull HttpHeaders headers,
@NotNull HttpStatusCode status,
@NotNull WebRequest request) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(AccessDeniedException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public ResponseEntity<?> AccessDeniedHandler(AccessDeniedException exception,
@NotNull HttpHeaders headers,
@NotNull HttpStatusCode status,
@NotNull WebRequest request) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.FORBIDDEN);
}
*/
}

0 comments on commit 36bc7d9

Please sign in to comment.