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;
}