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
© 2026 Devtiro Ltd. All rights reserved