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