Update Post Endpoint
Building on our post creation functionality from the previous lesson, we'll now implement the ability for writers to update their existing blog posts.
This endpoint will enable content creators to modify post content, change categories and tags, and toggle between draft and published states.
Update Request DTO
The UpdatePostRequestDto defines the structure and validation rules for post updates:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UpdatePostRequestDto {
@NotNull(message = "Post ID is required")
private UUID id;
@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 Model Implementation
The UpdatePostRequest class serves as our internal model for post updates:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UpdatePostRequest {
private UUID id;
private String title;
private String content;
private UUID categoryId;
@Builder.Default
private Set<UUID> tagIds = new HashSet<>();
private PostStatus status;
}Mapper Implementation
Let's implement the necessary methods on the PostMapper interface:
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface PostMapper {
// ...
UpdatePostRequest toUpdatePostRequest(UpdatePostRequestDto dto);
}Service Layer Enhancement
The PostService interface expands to include post update capability:
public interface PostService {
// ... existing methods ...
Post updatePost(UUID id, UpdatePostRequest updatePostRequest);
}Update Logic Implementation
The PostServiceImpl handles the complex logic of updating posts with proper validation:
@Override
@Transactional
public Post updatePost(UUID id, UpdatePostRequest updatePostRequest) {
Post existingPost = postRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Post does not exist with id " + id));
existingPost.setTitle(updatePostRequest.getTitle());
String postContent = updatePostRequest.getContent();
existingPost.setContent(postContent);
existingPost.setStatus(updatePostRequest.getStatus());
existingPost.setReadingTime(calculateReadingTime(postContent));
UUID updatePostRequestCategoryId = updatePostRequest.getCategoryId();
if(!existingPost.getCategory().getId().equals(updatePostRequestCategoryId)) {
Category newCategory = categoryService.getCategoryById(updatePostRequestCategoryId);
existingPost.setCategory(newCategory);
}
Set<UUID> existingTagIds = existingPost.getTags().stream().map(Tag::getId).collect(Collectors.toSet());
Set<UUID> updatePostRequestTagIds = updatePostRequest.getTagIds();
if(!existingTagIds.equals(updatePostRequestTagIds)) {
List<Tag> newTags = tagService.getTagByIds(updatePostRequestTagIds);
existingPost.setTags(new HashSet<>(newTags));
}
return postRepository.save(existingPost);
}Controller Implementation
The PostController handles the HTTP PUT requests for post updates:
@PutMapping(path = "/{id}")
public ResponseEntity<PostDto> updatePost(
@PathVariable UUID id,
@Valid @RequestBody UpdatePostRequestDto updatePostRequestDto) {
UpdatePostRequest updatePostRequest = postMapper.toUpdatePostRequest(updatePostRequestDto);
Post updatedPost = postService.updatePost(id, updatePostRequest);
PostDto updatedPostDto = postMapper.toDto(updatedPost);
return ResponseEntity.ok(updatedPostDto);
}Summary
- Implemented post update functionality with validation
- Created separate DTOs and domain models for clean separation of concerns