Refactor ProductCatalog with batch operations and organized namespaces#27
Refactor ProductCatalog with batch operations and organized namespaces#27
Conversation
…nd implement batch operations for categories and products - Update namespaces for clarity and consistency. - Introduce batch operations for creating, updating, and deleting categories and products. - Implement request and response models for batch operations. - Add validation and error handling for batch processing. - Create controllers for handling API requests related to categories and products. - Enhance specifications for querying categories with filters and sorting capabilities.
…ies and products - Introduce CategoriesController with endpoints for creating, updating, deleting, and retrieving categories. - Implement ProductsController with similar batch operations for products. - Add ProductDataController for managing product data documents, including image and video creation. - Enhance routing with shared templates for consistent API paths. - Update global usings to include shared routing features.
There was a problem hiding this comment.
Code Review
This pull request refactors the ProductCatalog module by reorganizing features into Category, Product, and ProductData sub-namespaces and consolidating feature-specific controllers into partial classes. Feedback was provided to address a breaking change in API route casing for ProductData and to correct the response type of the idempotent creation endpoint, which currently uses a fragile hardcoded path and lacks a corresponding GET endpoint.
| [ApiVersion(1.0)] | ||
| public sealed partial class ProductDataController(IMessageBus bus) : ApiControllerBase { } |
There was a problem hiding this comment.
The removal of the explicit [Route] attribute (previously "product-data") causes the route to default to ProductData based on the controller name. This introduces a breaking change to the API's URL casing (kebab-case to PascalCase). To maintain consistency with REST best practices and avoid breaking existing clients, consider adding an explicit kebab-case route attribute.
[ApiVersion(1.0)]
[Route("api/v{version:apiVersion}/product-data")]
public sealed partial class ProductDataController(IMessageBus bus) : ApiControllerBase { }| return Created( | ||
| $"/api/v{this.GetApiVersion()}/{ProductCatalogRouteTemplates.IdempotentPathSegment}", | ||
| result.Value | ||
| ); |
There was a problem hiding this comment.
The Created response uses a hardcoded path string which is fragile and doesn't account for application base paths. Furthermore, the Location header points to the collection endpoint (/idempotent) which only supports POST. Per HTTP standards, the Location header in a 201 Created response should point to a URI where the resource can be retrieved (typically a GET endpoint). Since no such endpoint is defined for this idempotent operation, returning Ok(result.Value) is more appropriate.
return Ok(result.Value);There was a problem hiding this comment.
Pull request overview
This PR refactors the ProductCatalog module structure by reorganizing features into clearer namespaces (Category/Product/ProductData), consolidating REST endpoints into shared partial controllers, and updating API consumers/tests to align with the new routing and namespaces.
Changes:
- Reorganized ProductCatalog feature namespaces (e.g.,
Features.Product.*,Features.Category.*,Features.ProductData.*) and updated references across src/tests. - Consolidated several REST controllers into partial controllers (e.g.,
ProductsController,CategoriesController,ProductDataController,PatchController,IdempotentController). - Updated integration tests to use the new ProductData route (
/api/v1/ProductData) and updated import paths accordingly.
Reviewed changes
Copilot reviewed 112 out of 112 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/APITemplate.Tests/Unit/Validators/UpdateProductRequestValidatorTests.cs | Updates namespace import for UpdateProducts validator tests. |
| tests/APITemplate.Tests/Unit/Validators/CreateProductRequestValidatorTests.cs | Updates namespace import for CreateProducts validator tests. |
| tests/APITemplate.Tests/Unit/ProductCatalog/ProductCatalogModuleTests.cs | Updates feature imports for reorganized Category/Product namespaces. |
| tests/APITemplate.Tests/Unit/ProductCatalog/PatchProductCommandHandlerTests.cs | Updates feature imports for PatchProduct and shared product feature namespace. |
| tests/APITemplate.Tests/Integration/Products/ProductDataControllerTests.cs | Updates ProductData endpoint URLs to new controller-based route. |
| tests/APITemplate.Tests/Integration/Postgres/PostgresSoftDeleteTests.cs | Updates ProductData delete URL to new ProductData route. |
| tests/APITemplate.Tests/Integration/Features/IdempotentControllerTests.cs | Updates import path for IdempotentCreate feature. |
| tests/APITemplate.Tests/Integration/Auth/UnauthorizedAccessTests.cs | Updates ProductData unauthorized endpoint URL to new route. |
| src/Modules/ProductCatalog/Repositories/ProductRepository.cs | Updates import to new Features.Product.GetProducts namespace. |
| src/Modules/ProductCatalog/Interfaces/IProductRepository.cs | Updates import to new Features.Product.GetProducts namespace. |
| src/Modules/ProductCatalog/GraphQL/Queries/ProductQueries.cs | Updates product query imports to new Product feature namespaces. |
| src/Modules/ProductCatalog/GraphQL/Queries/CategoryQueries.cs | Updates category query imports to new Category feature namespaces. |
| src/Modules/ProductCatalog/GraphQL/Mutations/ProductMutations.cs | Updates product mutation imports to new Product feature namespaces. |
| src/Modules/ProductCatalog/GlobalUsings.cs | Reorganizes global usings and introduces feature-scoped shared namespaces. |
| src/Modules/ProductCatalog/Features/Shared/Routing/ProductCatalogRouteTemplates.cs | Adds shared route fragment constants for ProductCatalog. |
| src/Modules/ProductCatalog/Features/ProductData/Shared/ProductDataResponse.cs | Moves ProductData response model into ProductData shared namespace. |
| src/Modules/ProductCatalog/Features/ProductData/Shared/ProductDataMappings.cs | Moves ProductData mapping helpers into ProductData shared namespace. |
| src/Modules/ProductCatalog/Features/ProductData/ProductDataController.cs | Introduces consolidated ProductData REST controller (partial). |
| src/Modules/ProductCatalog/Features/ProductData/GetProductDataById/ProductDataController.GetById.cs | Moves GetById endpoint into ProductDataController partial. |
| src/Modules/ProductCatalog/Features/ProductData/GetProductDataById/GetProductDataByIdQuery.cs | Moves query into Features.ProductData.GetProductDataById namespace. |
| src/Modules/ProductCatalog/Features/ProductData/GetProductData/ProductDataController.GetAll.cs | Moves GetAll endpoint into ProductDataController partial. |
| src/Modules/ProductCatalog/Features/ProductData/GetProductData/GetProductDataQuery.cs | Moves query into Features.ProductData.GetProductData namespace. |
| src/Modules/ProductCatalog/Features/ProductData/DeleteProductData/ProductDataController.Delete.cs | Moves Delete endpoint into ProductDataController partial. |
| src/Modules/ProductCatalog/Features/ProductData/DeleteProductData/ProductDataCascadeDeleteHandler.cs | Updates handler namespace under ProductData.DeleteProductData. |
| src/Modules/ProductCatalog/Features/ProductData/DeleteProductData/DeleteProductDataCommand.cs | Updates command namespace under ProductData.DeleteProductData. |
| src/Modules/ProductCatalog/Features/ProductData/CreateVideoProductData/ProductDataController.CreateVideo.cs | Moves CreateVideo endpoint into ProductDataController partial. |
| src/Modules/ProductCatalog/Features/ProductData/CreateVideoProductData/CreateVideoProductDataRequestValidator.cs | Updates validator namespace under ProductData.CreateVideoProductData. |
| src/Modules/ProductCatalog/Features/ProductData/CreateVideoProductData/CreateVideoProductDataRequest.cs | Updates request namespace under ProductData.CreateVideoProductData. |
| src/Modules/ProductCatalog/Features/ProductData/CreateVideoProductData/CreateVideoProductDataCommand.cs | Updates command namespace under ProductData.CreateVideoProductData. |
| src/Modules/ProductCatalog/Features/ProductData/CreateImageProductData/ProductDataController.CreateImage.cs | Moves CreateImage endpoint into ProductDataController partial. |
| src/Modules/ProductCatalog/Features/ProductData/CreateImageProductData/CreateImageProductDataRequestValidator.cs | Updates validator namespace under ProductData.CreateImageProductData. |
| src/Modules/ProductCatalog/Features/ProductData/CreateImageProductData/CreateImageProductDataRequest.cs | Updates request namespace under ProductData.CreateImageProductData. |
| src/Modules/ProductCatalog/Features/ProductData/CreateImageProductData/CreateImageProductDataCommand.cs | Updates command namespace under ProductData.CreateImageProductData. |
| src/Modules/ProductCatalog/Features/Product/ValidateProductExists/ValidateProductExistsQueryHandler.cs | Moves handler under Features.Product.ValidateProductExists. |
| src/Modules/ProductCatalog/Features/Product/UpdateProducts/UpdateProductsRequest.cs | Moves update batch request into Features.Product.UpdateProducts. |
| src/Modules/ProductCatalog/Features/Product/UpdateProducts/UpdateProductsCommand.cs | Moves update batch command into Features.Product.UpdateProducts. |
| src/Modules/ProductCatalog/Features/Product/UpdateProducts/UpdateProductRequestValidator.cs | Moves update request validator into Features.Product.UpdateProducts. |
| src/Modules/ProductCatalog/Features/Product/UpdateProducts/UpdateProductRequest.cs | Moves update request into Features.Product.UpdateProducts. |
| src/Modules/ProductCatalog/Features/Product/UpdateProducts/UpdateProductItemValidator.cs | Moves update item validator into Features.Product.UpdateProducts. |
| src/Modules/ProductCatalog/Features/Product/UpdateProducts/ProductsController.UpdateProducts.cs | Moves update endpoint into consolidated ProductsController partial. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductValidationHelper.cs | Moves shared validation helper into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductsResponse.cs | Moves products response model into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductSortFields.cs | Moves product sort field map into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductSearchFacetsResponse.cs | Moves facets response model into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductsByIdsWithLinksSpecification.cs | Moves spec into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductResponse.cs | Moves product response model into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductRequestValidatorBase.cs | Moves shared product validator base into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductPriceFacetSpecification.cs | Updates imports + namespace for product price facet spec. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductPriceFacetBucketResponse.cs | Moves bucket response model into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductMappings.cs | Moves product mapping helpers into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductCategoryFacetValue.cs | Moves category facet model into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/Shared/ProductCategoryFacetSpecification.cs | Updates imports + namespace for category facet spec. |
| src/Modules/ProductCatalog/Features/Product/Shared/IProductRequest.cs | Moves shared product request contract into Product shared namespace. |
| src/Modules/ProductCatalog/Features/Product/ProductsController.cs | Introduces consolidated Products REST controller (partial). |
| src/Modules/ProductCatalog/Features/Product/PatchProduct/PatchProductCommand.cs | Moves PatchProduct command into Product.PatchProduct namespace. |
| src/Modules/ProductCatalog/Features/Product/PatchProduct/PatchController.PatchProduct.cs | Moves Patch endpoint into consolidated PatchController partial and updates permission constant. |
| src/Modules/ProductCatalog/Features/Product/PatchProduct/PatchController.cs | Introduces consolidated Patch REST controller (partial). |
| src/Modules/ProductCatalog/Features/Product/PatchProduct/PatchableProductDtoValidator.cs | Moves validator namespace under Product.PatchProduct. |
| src/Modules/ProductCatalog/Features/Product/PatchProduct/PatchableProductDto.cs | Moves DTO namespace under Product.PatchProduct. |
| src/Modules/ProductCatalog/Features/Product/IdempotentCreate/IdempotentCreateResponse.cs | Moves idempotent response namespace under Product.IdempotentCreate. |
| src/Modules/ProductCatalog/Features/Product/IdempotentCreate/IdempotentCreateRequestValidator.cs | Moves validator namespace under Product.IdempotentCreate. |
| src/Modules/ProductCatalog/Features/Product/IdempotentCreate/IdempotentCreateRequest.cs | Moves request namespace under Product.IdempotentCreate. |
| src/Modules/ProductCatalog/Features/Product/IdempotentCreate/IdempotentCreateCommand.cs | Moves command namespace under Product.IdempotentCreate. |
| src/Modules/ProductCatalog/Features/Product/IdempotentCreate/IdempotentController.cs | Introduces consolidated Idempotent REST controller (partial). |
| src/Modules/ProductCatalog/Features/Product/IdempotentCreate/IdempotentController.Create.cs | Moves idempotent create endpoint into consolidated controller and changes response to 201 Created with Location. |
| src/Modules/ProductCatalog/Features/Product/GetProducts/ProductSpecification.cs | Moves specification namespace under Product.GetProducts. |
| src/Modules/ProductCatalog/Features/Product/GetProducts/ProductsController.GetProducts.cs | Moves GetProducts endpoint into consolidated ProductsController partial. |
| src/Modules/ProductCatalog/Features/Product/GetProducts/ProductFilterValidator.cs | Moves filter validator namespace under Product.GetProducts. |
| src/Modules/ProductCatalog/Features/Product/GetProducts/ProductFilterCriteria.cs | Moves filter criteria helpers namespace under Product.GetProducts. |
| src/Modules/ProductCatalog/Features/Product/GetProducts/ProductFilter.cs | Moves filter model namespace under Product.GetProducts. |
| src/Modules/ProductCatalog/Features/Product/GetProducts/GetProductsQuery.cs | Moves query namespace under Product.GetProducts. |
| src/Modules/ProductCatalog/Features/Product/GetProductById/ProductsController.GetProductById.cs | Moves GetById endpoint into consolidated ProductsController partial. |
| src/Modules/ProductCatalog/Features/Product/GetProductById/ProductByIdWithLinksSpecification.cs | Moves specification namespace under Product.GetProductById. |
| src/Modules/ProductCatalog/Features/Product/GetProductById/ProductByIdSpecification.cs | Moves specification namespace under Product.GetProductById. |
| src/Modules/ProductCatalog/Features/Product/GetProductById/GetProductByIdQuery.cs | Moves query namespace under Product.GetProductById. |
| src/Modules/ProductCatalog/Features/Product/DeleteProducts/ProductsController.DeleteProducts.cs | Moves delete endpoint into consolidated ProductsController partial. |
| src/Modules/ProductCatalog/Features/Product/DeleteProducts/DeleteProductsCommand.cs | Moves command namespace under Product.DeleteProducts. |
| src/Modules/ProductCatalog/Features/Product/CreateProducts/ProductsController.CreateProducts.cs | Moves create endpoint into consolidated ProductsController partial. |
| src/Modules/ProductCatalog/Features/Product/CreateProducts/CreateProductsRequest.cs | Moves create batch request namespace under Product.CreateProducts. |
| src/Modules/ProductCatalog/Features/Product/CreateProducts/CreateProductsCommand.cs | Moves create batch command namespace under Product.CreateProducts. |
| src/Modules/ProductCatalog/Features/Product/CreateProducts/CreateProductRequestValidator.cs | Moves validator namespace under Product.CreateProducts. |
| src/Modules/ProductCatalog/Features/Product/CreateProducts/CreateProductRequest.cs | Moves request namespace under Product.CreateProducts. |
| src/Modules/ProductCatalog/Features/Category/UpdateCategories/UpdateCategoryRequest.cs | Moves category update request into Category.UpdateCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/UpdateCategories/UpdateCategoryItemValidator.cs | Moves validator into Category.UpdateCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/UpdateCategories/UpdateCategoriesRequest.cs | Moves update batch request into Category.UpdateCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/UpdateCategories/UpdateCategoriesCommand.cs | Moves update batch command into Category.UpdateCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/UpdateCategories/CategoriesController.UpdateCategories.cs | Moves update endpoint into consolidated CategoriesController partial. |
| src/Modules/ProductCatalog/Features/Category/Shared/CategorySortFields.cs | Moves category sort field map into Category shared namespace. |
| src/Modules/ProductCatalog/Features/Category/Shared/CategoryResponse.cs | Moves category response model into Category shared namespace. |
| src/Modules/ProductCatalog/Features/Category/Shared/CategoryMappings.cs | Moves category mapping helpers into Category shared namespace. |
| src/Modules/ProductCatalog/Features/Category/Shared/CategoriesByIdsSpecification.cs | Moves spec into Category shared namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategoryStats/ProductCategoryStatsResponse.cs | Moves stats response into Category.GetCategoryStats namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategoryStats/GetCategoryStatsQuery.cs | Moves stats query into Category.GetCategoryStats namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategoryStats/CategoriesController.GetCategoryStats.cs | Moves stats endpoint into consolidated CategoriesController partial. |
| src/Modules/ProductCatalog/Features/Category/GetCategoryById/GetCategoryByIdQuery.cs | Moves query into Category.GetCategoryById namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategoryById/CategoryByIdSpecification.cs | Moves spec into Category.GetCategoryById namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategoryById/CategoriesController.GetCategoryById.cs | Moves get-by-id endpoint into consolidated CategoriesController partial. |
| src/Modules/ProductCatalog/Features/Category/GetCategories/GetCategoriesQuery.cs | Moves query into Category.GetCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategories/CategorySpecification.cs | Moves spec into Category.GetCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategories/CategoryFilterValidator.cs | Moves filter validator into Category.GetCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategories/CategoryFilterCriteria.cs | Moves filter criteria helpers into Category.GetCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategories/CategoryFilter.cs | Moves filter model into Category.GetCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/GetCategories/CategoriesController.GetCategories.cs | Moves list endpoint into consolidated CategoriesController partial. |
| src/Modules/ProductCatalog/Features/Category/DeleteCategories/DeleteCategoriesCommand.cs | Moves delete command into Category.DeleteCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/DeleteCategories/CategoriesController.DeleteCategories.cs | Moves delete endpoint into consolidated CategoriesController partial. |
| src/Modules/ProductCatalog/Features/Category/CreateCategories/CreateCategoryRequestValidator.cs | Moves validator into Category.CreateCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/CreateCategories/CreateCategoryRequest.cs | Moves request into Category.CreateCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/CreateCategories/CreateCategoriesRequest.cs | Moves create batch request into Category.CreateCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/CreateCategories/CreateCategoriesCommand.cs | Moves create batch command into Category.CreateCategories namespace. |
| src/Modules/ProductCatalog/Features/Category/CreateCategories/CategoriesController.CreateCategories.cs | Moves create endpoint into consolidated CategoriesController partial. |
| src/Modules/ProductCatalog/Features/Category/CategoriesController.cs | Introduces consolidated Categories REST controller (partial). |
| src/APITemplate/Api/Program.cs | Updates CreateProducts feature import to new Product namespace. |
Comments suppressed due to low confidence (1)
src/Modules/ProductCatalog/Features/Product/IdempotentCreate/IdempotentController.Create.cs:20
IdempotentCreateCommandpersists aProductentity, but this endpoint is protected byPermission.Examples.Create. This is likely the wrong authorization policy (could unintentionally allow/deny product creation). Consider switching this toPermission.Products.Create(or a dedicated permission for idempotent product creation if you want it distinct).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| [ApiVersion(1.0)] | ||
| public sealed partial class ProductDataController(IMessageBus bus) : ApiControllerBase { } |
There was a problem hiding this comment.
ApiControllerBase supplies [Route("api/v{version:apiVersion}/[controller]")], so introducing ProductDataController changes the public endpoint from the previous kebab-case /api/v{version}/product-data to /api/v{version}/ProductData (hyphen removed). If existing clients rely on /product-data, consider adding an additional [Route("api/v{version:apiVersion}/product-data")] on this controller to keep backwards compatibility while still allowing the new route.
Organize ProductCatalog features into distinct namespaces for clarity and consistency. Implement batch operations for creating, updating, and deleting categories and products, along with necessary validation and error handling. Introduce controllers for managing API requests related to these operations. Enhance querying capabilities for categories with filters and sorting.