diff --git a/pom.xml b/pom.xml index d85e171..9e03205 100644 --- a/pom.xml +++ b/pom.xml @@ -89,6 +89,12 @@ runtime + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.1.0 + diff --git a/src/main/java/com/springboot/blog/SpringbootBlogRestApiApplication.java b/src/main/java/com/springboot/blog/SpringbootBlogRestApiApplication.java index 3e9351a..249a598 100644 --- a/src/main/java/com/springboot/blog/SpringbootBlogRestApiApplication.java +++ b/src/main/java/com/springboot/blog/SpringbootBlogRestApiApplication.java @@ -1,11 +1,36 @@ package com.springboot.blog; +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; import org.modelmapper.ModelMapper; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication +@OpenAPIDefinition( + info = @Info( + title = "Spring Boot Blog App REST APIs", + description = "Spring Boot Blog App REST APIs documentation", + version = "v1.0", + contact = @Contact( + name = "Adilet Kozubaev", + email = "adiletkdev@gmail.com", + url = "https://www.******.net" + ), + license = @License( + name = "Apache 2.0", + url = "https://www.******.net/license" + ) + ), + externalDocs = @ExternalDocumentation( + description = "Spring Boot Blog App documentation", + url = "https://github.com/adiletkdev/springboot-blog-rest-api" + ) +) public class SpringbootBlogRestApiApplication { @Bean diff --git a/src/main/java/com/springboot/blog/config/SecurityConfig.java b/src/main/java/com/springboot/blog/config/SecurityConfig.java index 85c8bbf..72c60c3 100644 --- a/src/main/java/com/springboot/blog/config/SecurityConfig.java +++ b/src/main/java/com/springboot/blog/config/SecurityConfig.java @@ -2,6 +2,8 @@ import com.springboot.blog.security.JwtAuthenticationEntryPoint; import com.springboot.blog.security.JwtAuthenticationFilter; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.security.SecurityScheme; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -22,6 +24,12 @@ @Configuration @EnableMethodSecurity +@SecurityScheme( + name = "Bearer Authentication", + type = SecuritySchemeType.HTTP, + bearerFormat = "JWT", + scheme = "bearer" +) public class SecurityConfig { private UserDetailsService userDetailsService; @@ -56,6 +64,8 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { //authorize.anyRequest().authenticated() authorize.requestMatchers(HttpMethod.GET, "/api/**").permitAll() .requestMatchers("/api/auth/**").permitAll() + .requestMatchers("/swagger-ui/**").permitAll() + .requestMatchers("/v3/api-docs/**").permitAll() .anyRequest().authenticated() ).exceptionHandling(exception -> exception diff --git a/src/main/java/com/springboot/blog/controller/PostController.java b/src/main/java/com/springboot/blog/controller/PostController.java index 1c97565..7363118 100644 --- a/src/main/java/com/springboot/blog/controller/PostController.java +++ b/src/main/java/com/springboot/blog/controller/PostController.java @@ -4,6 +4,10 @@ import com.springboot.blog.payload.PostResponse; import com.springboot.blog.service.PostService; import com.springboot.blog.utils.AppConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -14,6 +18,9 @@ @RestController @RequestMapping("/api/posts") +@Tag( + name = "CRUD REST APIs for Post Resource" +) public class PostController { private PostService postService; @@ -23,6 +30,17 @@ public PostController(PostService postService) { } // create blog post + @Operation( + summary = "Create Post REST API", + description = "Create Post REST API is used to save post into database" + ) + @ApiResponse( + responseCode = "201", + description = "Http Status 201 CREATED" + ) + @SecurityRequirement( + name = "Bearer Authentication" + ) @PreAuthorize("hasRole('ADMIN')") @PostMapping public ResponseEntity createPost(@Valid @RequestBody PostDto postDto) { @@ -30,6 +48,14 @@ public ResponseEntity createPost(@Valid @RequestBody PostDto postDto) { } // get all posts rest api + @Operation( + summary = "Get All Posts REST API", + description = "Get All Posts REST API is used to fetch all the posts from the database" + ) + @ApiResponse( + responseCode = "200", + description = "Http Status 200 SUCCESS" + ) @GetMapping public PostResponse getAllPosts( @RequestParam(value = "pageNo", defaultValue = AppConstants.DEFAULT_PAGE_NUMBER, required = false) int pageNo, @@ -41,12 +67,31 @@ public PostResponse getAllPosts( } // get post by id + @Operation( + summary = "Get Post by Id REST API", + description = "Get Post by Id REST API is used to get single post from the database" + ) + @ApiResponse( + responseCode = "200", + description = "Http Status 200 SUCCESS" + ) @GetMapping("/{id}") public ResponseEntity getPostId(@PathVariable(name = "id") long id) { return ResponseEntity.ok(postService.getPostById(id)); } // update post by id rest api + @Operation( + summary = "Update Post REST API", + description = "Update Post REST API is used to update a particular post in the database" + ) + @ApiResponse( + responseCode = "200", + description = "Http Status 200 SUCCESS" + ) + @SecurityRequirement( + name = "Bearer Authentication" + ) @PreAuthorize("hasRole('ADMIN')") @PutMapping("/{id}") public ResponseEntity updatePost( @@ -59,6 +104,17 @@ public ResponseEntity updatePost( } // delete post rest api + @Operation( + summary = "Delete Post REST API", + description = "Delete Post REST API is used to delete a particular post from the database" + ) + @ApiResponse( + responseCode = "200", + description = "Http Status 200 SUCCESS" + ) + @SecurityRequirement( + name = "Bearer Authentication" + ) @PreAuthorize("hasRole('ADMIN')") @DeleteMapping("/{id}") public ResponseEntity deletePost(@PathVariable(name = "id") long id) { diff --git a/src/main/java/com/springboot/blog/payload/PostDto.java b/src/main/java/com/springboot/blog/payload/PostDto.java index 22f3e27..04c4a13 100644 --- a/src/main/java/com/springboot/blog/payload/PostDto.java +++ b/src/main/java/com/springboot/blog/payload/PostDto.java @@ -1,31 +1,47 @@ package com.springboot.blog.payload; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Size; import lombok.Data; import java.util.Set; +@Schema( + description = "PostDto Model Information" +) @Data public class PostDto { private long id; + @Schema( + description = "Blog Post Title" + ) // title should not be null or empty // title should have at least 2 characters @NotEmpty @Size(min = 2, message = "Post title should have at least 2 characters") private String title; + @Schema( + description = "Blog Post Description" + ) // post description should be null or empty // post description should have at least 10 characters @NotEmpty @Size(min = 10, message = "Post description should have at least 10 characters") private String description; + @Schema( + description = "Blog Post Content" + ) // post content should not be null or empty @NotEmpty private String content; private Set comments; + @Schema( + description = "Blog Post Category" + ) private Long categoryId; }