Create Post Endpoint

Building on our post listing functionality from previous lessons, we'll now implement the ability for authenticated users to create new blog posts.

This endpoint will enable writers to compose and save both draft and published content with proper categorization and tagging.

Request Data Transfer Object

The CreatePostRequestDto class defines the structure and validation rules for incoming post creation requests:

@Data @AllArgsConstructor @NoArgsConstructor @Builder public class CreatePostRequestDto { @NotBlank(message = "Title is required") @Size(min = 3, max = 200, message = "Title must be between {min} and {max} characters") private String title; @NotBlank(message = "Content is required") @Size(min = 10, max = 50000, message = "Content must be between {min} and {max} characters") private String content; @NotNull(message = "Category ID is required") private UUID categoryId; @Builder.Default @Size(max = 10, message = "Maximum {max} tags allowed") private Set<UUID> tagIds = new HashSet<>(); @NotNull(message = "Status is required") private PostStatus status; }

Domain Request Model

The CreatePostRequest class serves as our internal domain model for post creation:

@Data @AllArgsConstructor @NoArgsConstructor @Builder public class CreatePostRequest { private String title; private String content; private UUID categoryId; @Builder.Default private Set<UUID> tagIds = new HashSet<>(); private PostStatus status; }

Mapper Configuration

The PostMapper interface handles the conversion between DTOs and domain objects:

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) public interface PostMapper { // ... CreatePostRequest toCreatePostRequest(CreatePostRequestDto dto); }

Service Layer Definition

The PostService interface defines our post creation contract:

public interface PostService { // ... Post createPost(User user, CreatePostRequest createPostRequest); }

Service Implementation

The PostServiceImpl handles the core logic of post creation:

@Override @Transactional public Post createPost(User user, CreatePostRequest createPostRequest) { Post newPost = new Post(); newPost.setTitle(createPostRequest.getTitle()); newPost.setContent(createPostRequest.getContent()); newPost.setStatus(createPostRequest.getStatus()); newPost.setAuthor(user); newPost.setReadingTime(calculateReadingTime(createPostRequest.getContent())); Category category = categoryService.getCategoryById(createPostRequest.getCategoryId()); newPost.setCategory(category); Set<UUID> tagIds = createPostRequest.getTagIds(); List<Tag> tags = tagService.getTagByIds(tagIds); newPost.setTags(new HashSet<>(tags)); return postRepository.save(newPost); }

Controller Implementation

The PostController handles HTTP POST requests for creating new posts:

@PostMapping public ResponseEntity<PostDto> createPost( @Valid @RequestBody CreatePostRequestDto createPostRequestDto, @RequestAttribute UUID userId) { User loggedInUser = userService.getUserById(userId); CreatePostRequest createPostRequest = postMapper.toCreatePostRequest(createPostRequestDto); Post createdPost = postService.createPost(loggedInUser, createPostRequest); PostDto createdPostDto = postMapper.toDto(createdPost); return new ResponseEntity<>(createdPostDto, HttpStatus.CREATED); }

Summary

  • Implemented post creation with validation
  • Added reading time calculation
© 2026 Devtiro Ltd. All rights reserved