Create Category Endpoint

Building on our list categories endpoint from the previous lesson, we'll now implement the ability to create new categories through our API.

This functionality will enable content organization by allowing users to define new category groupings for blog posts.

The create endpoint will validate inputs and prevent duplicate categories, ensuring data integrity in our blog platform.

Request Object Implementation

The create category request requires validation to ensure data quality and consistency.

Let's create the CreateCategoryRequest class to define the structure and validation rules:

package com.devtiro.blog.domain.dtos; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class CreateCategoryRequest { @NotBlank(message = "Category name is required") @Size(min = 2, max = 50, message = "Category name must be between {min} and {max} characters") @Pattern(regexp = "^[\\w\\s-]+$", message = "Category name can only contain letters, numbers, spaces, and hyphens") private String name; }

Mapper Extension

The CategoryMapper interface needs to handle converting request objects to entities.

Let's add the conversion method to our existing mapper:

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) public interface CategoryMapper { // ... existing methods ... Category toEntity(CreateCategoryRequest createCategoryRequest); }

Service Layer Implementation

The service layer must handle the business logic of creating categories while preventing duplicates.

First, let's add the method to our service interface:

public interface CategoryService { // ... existing methods ... Category createCategory(Category category); }

Now we can implement the creation logic in our service implementation:

@Service @RequiredArgsConstructor @Transactional(readOnly = true) public class CategoryServiceImpl implements CategoryService { private final CategoryRepository categoryRepository; // ... existing methods ... @Override @Transactional public Category createCategory(Category category) { // Check if category with same name already exists if (categoryRepository.existsByNameIgnoreCase(category.getName())) { throw new IllegalArgumentException("Category already exists with name: " + category.getName()); } return categoryRepository.save(category); } }

Repository Enhancement

The repository needs a method to check for existing categories by name.

Let's add this method to our repository interface:

@Repository public interface CategoryRepository extends JpaRepository<Category, UUID> { // ... existing methods ... boolean existsByNameIgnoreCase(String name); }

Controller Implementation

Finally, we can implement the controller method to handle category creation requests:

@RestController @RequestMapping("/api/v1/categories") @RequiredArgsConstructor public class CategoryController { private final CategoryService categoryService; private final CategoryMapper categoryMapper; // ... existing methods ... @PostMapping public ResponseEntity<CategoryDto> createCategory( @Valid @RequestBody CreateCategoryRequest createCategoryRequest) { Category category = categoryMapper.toEntity(createCategoryRequest); Category savedCategory = categoryService.createCategory(category); return new ResponseEntity<>( categoryMapper.toDto(savedCategory), HttpStatus.CREATED ); } }

Summary

  • Implemented category creation with input validation and duplicate prevention
  • Extended mapper interface to handle request-to-entity conversion
  • Added transactional service method for category creation
  • Enhanced repository with case-insensitive name existence check
  • Created POST endpoint returning HTTP 201 status for successful creation
© 2026 Devtiro Ltd. All rights reserved