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