Skip to content

[API] Fix HTTP error codes for cart operations (fixes #18475)#18476

Merged
NoResponseMate merged 1 commit intoSylius:2.1from
Rafikooo:fix/api-cart-error-codes
Nov 3, 2025
Merged

[API] Fix HTTP error codes for cart operations (fixes #18475)#18476
NoResponseMate merged 1 commit intoSylius:2.1from
Rafikooo:fix/api-cart-error-codes

Conversation

@Rafikooo
Copy link
Copy Markdown
Contributor

@Rafikooo Rafikooo commented Oct 27, 2025

Summary

  • Replace generic 500 errors with proper 4xx HTTP codes for cart API operations
  • Add dedicated exception classes for better error handling
  • Ensure consistent error responses across cart endpoints

Changes

  • Add CartNotFoundException returning HTTP 422 for non-existent carts
  • Add ProductVariantNotFoundException returning HTTP 422 for invalid product variants
  • Update AddItemToCartHandler to throw dedicated exceptions instead of InvalidArgumentException
  • Update BlameCartHandler to use ConflictHttpException (409) for cart conflicts
  • Add functional tests to verify proper HTTP error codes

Why 422 instead of 404?

For POST operations that cannot be processed due to missing resources, 422 Unprocessable Entity is more semantically correct than 404 Not Found, as it indicates the request cannot be processed rather than the endpoint not existing.

Fixes #18475

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling and HTTP status codes for cart operations with clearer messages when carts or product variants cannot be found.
  • Tests

    • Added test coverage for error scenarios during cart item addition and checkout operations.

@Rafikooo Rafikooo requested review from a team as code owners October 27, 2025 10:15
@probot-autolabeler probot-autolabeler bot added the API APIs related issues and PRs. label Oct 27, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 27, 2025

Walkthrough

The PR refactors exception handling in cart command handlers to throw domain-specific HTTP exceptions (UnprocessableCartException, ProductVariantUnprocessableException, NotFoundHttpException, ConflictHttpException) instead of generic InvalidArgumentException, and adds integration tests validating error responses for cart and product variant not-found scenarios.

Changes

Cohort / File(s) Summary
New Exception Classes
src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php, src/Sylius/Bundle/ApiBundle/Exception/ProductVariantUnprocessableException.php
Added two final exception classes extending UnprocessableEntityHttpException to represent HTTP 422 errors for unprocessable cart/product variant scenarios. Each accepts optional previous throwable, code, and headers parameters.
Command Handler Updates
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php, src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php
Replaced InvalidArgumentException with HTTP-friendly exceptions: ProductVariantUnprocessableException and UnprocessableCartException for missing resources, NotFoundHttpException for missing customer, and ConflictHttpException for occupied carts.
Unit Test Updates
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php, src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php
Updated exception type expectations in tests to match new exception classes and removed MessageHandlerAttributeTrait usage from test classes.
Integration Tests
tests/Api/Shop/Checkout/CartTest.php
Added two new API tests validating HTTP 422 responses with proper hydra descriptions when adding items to non-existent carts or with non-existent product variants.

Sequence Diagram

sequenceDiagram
    autonumber
    participant Client
    participant API as API Router
    participant Handler as AddItemToCartHandler
    participant Repo as Cart Repository
    
    Client->>API: POST /api/v2/shop/orders/{invalidToken}/items
    API->>Handler: AddItemToCart (invalid token)
    Handler->>Repo: find cart by token
    Repo-->>Handler: null
    
    rect rgb(255, 235, 205)
    Note over Handler: OLD: throw InvalidArgumentException
    Handler-->>API: 500 Internal Server Error
    end
    
    rect rgb(200, 255, 200)
    Note over Handler: NEW: throw UnprocessableCartException
    Handler-->>API: 422 Unprocessable Entity
    end
    
    API-->>Client: HTTP 422 + hydra:description
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Exception class creation: Two new, identical-pattern exception classes—straightforward but require verification of message text and parent class usage.
  • Handler logic changes: Two handlers with different exception mappings per scenario (missing variant, missing cart, missing customer, occupied cart)—each mapping requires separate reasoning.
  • Test exception expectations: Multiple test methods across two files changing from InvalidArgumentException to new types—repetitive but require verification against implementation.
  • Integration tests: Two new API-level tests with setup and assertions—verify correct HTTP status codes and response structure.

Areas requiring extra attention:

  • Verify that exception message text in UnprocessableCartException and ProductVariantUnprocessableException matches what the API specs expect.
  • Confirm that NotFoundHttpException and ConflictHttpException are the correct HTTP exception types (4xx status codes) in BlameCartHandler.
  • Validate integration test setup (fixtures, headers) matches the test suite conventions.
  • Check that the HTTP status codes (422, 404, 409) align with Symfony HTTP exception mappings.

Poem

🐰 A rabbit hops through error flows so grand,
Where 500s now become 422 across the land!
No more silent 5's to make folk weep,
Just honest 4's, the promises we keep!
Cart and variant now speak clear and true, 🎉
What a lovely refactor—hooray for you!

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title '[API] Fix HTTP error codes for cart operations (fixes #18475)' clearly and specifically describes the main change: correcting HTTP error codes returned by cart API operations. The title is concise, directly related to the core change in the changeset (replacing 500 errors with appropriate 4xx codes), and provides sufficient context for teammates to understand the primary objective.
Linked Issues check ✅ Passed The pull request successfully addresses all coding requirements from issue #18475. The implementation adds dedicated exception classes (UnprocessableCartException and ProductVariantUnprocessableException) that extend UnprocessableEntityHttpException to return HTTP 422 errors instead of 500s. The AddItemToCartHandler has been updated to throw these domain-specific exceptions for missing carts and product variants, BlameCartHandler now uses ConflictHttpException (409) for cart conflicts, and comprehensive functional tests have been added to verify correct HTTP error codes are returned for all specified scenarios.
Out of Scope Changes check ✅ Passed All changes in the pull request are directly scoped to the objective of fixing HTTP error codes for cart operations. The modifications include adding two new exception classes, updating two command handlers to use these exceptions, updating corresponding test files, and adding functional tests. Each change is necessary and directly supports the goal of replacing 500 errors with proper 4xx HTTP codes. No extraneous changes unrelated to error code handling are present.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 27, 2025

❌ Preview Environment deleted from Bunnyshell

Available commands:

  • 🚀 /bns:deploy to redeploy the environment

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (1)

28-30: Remove unused import.

UnprocessableEntityHttpException is imported but not used in this test file.

Apply this diff:

 use Sylius\Bundle\ApiBundle\Exception\CartNotFoundException;
 use Sylius\Bundle\ApiBundle\Exception\ProductVariantNotFoundException;
-use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d23d648 and f2c955f.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php (2 hunks)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (2 hunks)
  • src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1 hunks)
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1 hunks)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (3 hunks)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php (3 hunks)
  • tests/Api/Shop/Checkout/CartTest.php (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{php,yaml,yml,xml,twig}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation in PHP, YAML, XML, and Twig files

Files:

  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php
  • tests/Api/Shop/Checkout/CartTest.php
**/*.php

📄 CodeRabbit inference engine (AGENTS.md)

**/*.php: Use modern PHP 8.2+ syntax and features
Declare strict_types=1 in all PHP files
Follow the Sylius Coding Standard
Do not use deprecated features from PHP, Symfony, or Sylius
Use final for all classes, except entities and repositories
Use readonly for immutable services and value objects
Add type declarations for all properties, arguments, and return values
Use camelCase for variables and method names
Use SCREAMING_SNAKE_CASE for constants
Use fast returns instead of unnecessary nesting
Use trailing commas in multi-line arrays and argument lists
Order array keys alphabetically where applicable
Use PHPDoc only when necessary (e.g., @var Collection)
Group class elements in order: constants, properties, constructor, public, protected, private methods
Group getter and setter methods for the same properties together
Suffix interfaces with Interface and traits with Trait
Use use statements for all non-global classes
Sort use imports alphabetically and group by type (classes, functions, constants)

Files:

  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php
  • tests/Api/Shop/Checkout/CartTest.php
tests/**/*Test.php

📄 CodeRabbit inference engine (AGENTS.md)

Use PHPUnit for unit and functional testing

Files:

  • tests/Api/Shop/Checkout/CartTest.php
🧬 Code graph analysis (7)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
  • __construct (20-26)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
  • __construct (20-26)
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (1)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
  • CartNotFoundException (18-27)
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php (2)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
  • CartNotFoundException (18-27)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
  • ProductVariantNotFoundException (18-27)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php (3)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
  • CartNotFoundException (18-27)
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php (1)
  • __invoke (45-69)
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (1)
  • __invoke (41-64)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (2)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
  • CartNotFoundException (18-27)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
  • ProductVariantNotFoundException (18-27)
tests/Api/Shop/Checkout/CartTest.php (1)
tests/Api/JsonApiTestCase.php (2)
  • setUpDefaultPostHeaders (95-101)
  • requestPost (169-182)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Static checks / PHP 8.4, Symfony ^7.3
🔇 Additional comments (18)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)

1-27: LGTM! Exception class follows best practices.

The implementation is clean and consistent with the existing ProductVariantNotFoundException pattern. The use of 422 Unprocessable Entity for a missing cart aligns with the PR's rationale for POST operations where the endpoint exists but the resource cannot be processed.

src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php (3)

17-18: Good addition of domain-specific exception imports.


50-52: Improved error handling with domain-specific exception.

The change from generic InvalidArgumentException to ProductVariantNotFoundException provides clearer semantics and appropriate HTTP 422 response.


57-59: Improved error handling with domain-specific exception.

The change from generic InvalidArgumentException to CartNotFoundException provides clearer semantics and appropriate HTTP 422 response.

src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (2)

97-97: Test correctly updated for new exception type.


116-116: Test correctly updated for new exception type.

src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (5)

17-17: Appropriate import for domain-specific exception.


23-24: Good addition of HTTP-specific exception imports.


46-48: Appropriate use of NotFoundHttpException (404) for missing user.


53-55: Appropriate use of CartNotFoundException (422) for missing cart.

Consistent with the new error handling pattern across cart operations.


57-59: Excellent use of ConflictHttpException (409) for cart conflicts.

HTTP 409 is semantically correct when the cart already has an assigned customer.

src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php (4)

26-28: Appropriate imports for updated exception types.


85-85: Test correctly updated to expect ConflictHttpException.


95-95: Test correctly updated to expect CartNotFoundException.


101-101: Test correctly updated to expect NotFoundHttpException.

src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)

1-27: LGTM! Exception class follows best practices.

The implementation is clean and consistent with CartNotFoundException. Both exception classes follow the same pattern and adhere to coding guidelines.

tests/Api/Shop/Checkout/CartTest.php (2)

626-650: Excellent integration test for cart-not-found scenario.

The test properly verifies that a 422 status is returned with the expected error message when attempting to add an item to a non-existing cart.


652-679: Integration test may not exercise handler's ProductVariantNotFoundException.

The test correctly verifies that a 422 response is returned, but the comment on Line 675 reveals that API Platform's IRI validation is likely catching the invalid product variant IRI before the handler executes. This means ProductVariantNotFoundException in the handler may not be tested at this integration level.

Note: The handler's ProductVariantNotFoundException is properly tested at the unit level in AddItemToCartHandlerTest::testThrowsAnExceptionIfProductIsNotFound().

@Rafikooo Rafikooo force-pushed the fix/api-cart-error-codes branch 2 times, most recently from b1f8ed2 to 65f7e71 Compare October 27, 2025 10:29
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (1)

47-59: Exception semantics look good; consider message consistency and confirm 404 vs 422 policy.

  • 404 for missing customer, 422 for missing cart, 409 for assigned customer: OK, but please confirm the policy that user-not-found remains 404 while cart-not-found is 422 for POST-like flows to avoid mixed semantics across endpoints.

  • Minor copy consistency with other messages (“…has not been found.” + period). Optional polish:

-throw new NotFoundHttpException('There is currently no customer with given email');
+throw new NotFoundHttpException('Customer with the given email address has not been found.');
-throw new ConflictHttpException('There is an assigned customer to this cart');
+throw new ConflictHttpException('There is already an assigned customer to this cart.');
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)

18-26: LGTM; optional: centralize message as a constant for reuse.

Current implementation is correct and aligns with the 422 strategy. For consistency and reuse across tests and code, consider a constant:

 final class CartNotFoundException extends UnprocessableEntityHttpException
 {
+    private const MESSAGE = 'Cart with the given token has not been found.';
+
     public function __construct(
         ?\Throwable $previous = null,
         int $code = 0,
         array $headers = [],
     ) {
-        parent::__construct('Cart with given token has not been found.', $previous, $code, $headers);
+        parent::__construct(self::MESSAGE, $previous, $code, $headers);
     }
 }
tests/Api/Shop/Checkout/CartTest.php (1)

626-650: Good negative test for missing cart; asserts 422 and useful description.

Minor hardening: also assert the JSON-LD error shape (e.g., presence of 'hydra:title' and '@type' = 'hydra:Error') to avoid coupling solely to message text.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1f8ed2 and 65f7e71.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php (2 hunks)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (2 hunks)
  • src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1 hunks)
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1 hunks)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (3 hunks)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php (3 hunks)
  • tests/Api/Shop/Checkout/CartTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{php,yaml,yml,xml,twig}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation in PHP, YAML, XML, and Twig files

Files:

  • tests/Api/Shop/Checkout/CartTest.php
  • src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php
tests/**/*Test.php

📄 CodeRabbit inference engine (AGENTS.md)

Use PHPUnit for unit and functional testing

Files:

  • tests/Api/Shop/Checkout/CartTest.php
**/*.php

📄 CodeRabbit inference engine (AGENTS.md)

**/*.php: Use modern PHP 8.2+ syntax and features
Declare strict_types=1 in all PHP files
Follow the Sylius Coding Standard
Do not use deprecated features from PHP, Symfony, or Sylius
Use final for all classes, except entities and repositories
Use readonly for immutable services and value objects
Add type declarations for all properties, arguments, and return values
Use camelCase for variables and method names
Use SCREAMING_SNAKE_CASE for constants
Use fast returns instead of unnecessary nesting
Use trailing commas in multi-line arrays and argument lists
Order array keys alphabetically where applicable
Use PHPDoc only when necessary (e.g., @var Collection)
Group class elements in order: constants, properties, constructor, public, protected, private methods
Group getter and setter methods for the same properties together
Suffix interfaces with Interface and traits with Trait
Use use statements for all non-global classes
Sort use imports alphabetically and group by type (classes, functions, constants)

Files:

  • tests/Api/Shop/Checkout/CartTest.php
  • src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php
🧬 Code graph analysis (4)
tests/Api/Shop/Checkout/CartTest.php (1)
tests/Api/JsonApiTestCase.php (2)
  • setUpDefaultPostHeaders (95-101)
  • requestPost (169-182)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
  • __construct (20-26)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
  • __construct (20-26)
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (1)
src/Sylius/Bundle/ApiBundle/Exception/CartNotFoundException.php (1)
  • CartNotFoundException (18-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Static checks / PHP 8.4, Symfony ^7.3
  • GitHub Check: Static checks / PHP 8.3, Symfony ^6.4
🔇 Additional comments (1)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)

18-26: LGTM; verify test-message alignment to avoid brittleness.

Implementation is fine. Optional constant for reuse:

 final class ProductVariantNotFoundException extends UnprocessableEntityHttpException
 {
+    private const MESSAGE = 'Product variant with the given code has not been found.';
+
     public function __construct(
         ?\Throwable $previous = null,
         int $code = 0,
         array $headers = [],
     ) {
-        parent::__construct('Product variant with given code has not been found.', $previous, $code, $headers);
+        parent::__construct(self::MESSAGE, $previous, $code, $headers);
     }
 }

The new API test expects a description containing “does not exist”; if this exception is the source, the message won’t match. Please confirm which layer produces that string and align either the message or the test for stability.

@Rafikooo Rafikooo force-pushed the fix/api-cart-error-codes branch from 65f7e71 to 1e5acc3 Compare October 29, 2025 10:55
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/Api/Shop/Checkout/CartTest.php (1)

675-678: Message assertion brittle; align with new exception text or use a tolerant match.

ProductVariantNotFoundException says “has not been found.” This “does not exist” check may fail.

Use a regex tolerant to both phrasings:

-        $this->assertStringContainsString('does not exist', $response['hydra:description']);
+        $this->assertMatchesRegularExpression('/(does not exist|has not been found)/i', $response['hydra:description']);

Alternatively, assert only the 422 code and machine fields.

🧹 Nitpick comments (4)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (1)

28-29: Sort imports alphabetically for consistency.

Place ProductVariantNotFoundException before UnprocessableCartException.

As per coding guidelines.

-use Sylius\Bundle\ApiBundle\Exception\UnprocessableCartException;
-use Sylius\Bundle\ApiBundle\Exception\ProductVariantNotFoundException;
+use Sylius\Bundle\ApiBundle\Exception\ProductVariantNotFoundException;
+use Sylius\Bundle\ApiBundle\Exception\UnprocessableCartException;
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (1)

17-25: Sort use imports alphabetically.

Reorder for consistency.

As per coding guidelines.

-use Sylius\Bundle\ApiBundle\Command\Cart\BlameCart;
-use Sylius\Bundle\ApiBundle\Exception\UnprocessableCartException;
+use Sylius\Bundle\ApiBundle\Command\Cart\BlameCart;
+use Sylius\Bundle\ApiBundle\Exception\UnprocessableCartException;
 use Sylius\Component\Core\Model\OrderInterface;
 use Sylius\Component\Core.Model\ShopUserInterface;
 use Sylius\Component\Core\Repository\OrderRepositoryInterface;
 use Sylius\Component\Order\Processor\OrderProcessorInterface;
 use Sylius\Component\User\Repository\UserRepositoryInterface;
-use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\Messenger\Attribute\AsMessageHandler;
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php (2)

26-28: Sort imports alphabetically.

Keep Symfony exception imports ordered and grouped.

-use Sylius\Bundle\ApiBundle\Exception\UnprocessableCartException;
-use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Sylius\Bundle\ApiBundle\Exception\UnprocessableCartException;
+use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

85-101: Good: tests assert specific HTTP-friendly exceptions.

Expectations for 409/422/404 paths align with handler behavior. Optionally stub null returns explicitly for readability.

     public function testThrowsAnExceptionIfCartHasNotBeenFound(): void
     {
         $this->shopUserRepository->expects(self::once())
             ->method('findOneByEmail')
             ->with('sylius@example.com')
             ->willReturn($this->user);
+        $this->orderRepository->expects(self::once())
+            ->method('findCartByTokenValue')
+            ->with('TOKEN')
+            ->willReturn(null);
         self::expectException(UnprocessableCartException::class);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65f7e71 and 1e5acc3.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php (2 hunks)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (2 hunks)
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1 hunks)
  • src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1 hunks)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (3 hunks)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php (3 hunks)
  • tests/Api/Shop/Checkout/CartTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{php,yaml,yml,xml,twig}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation in PHP, YAML, XML, and Twig files

Files:

  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php
  • tests/Api/Shop/Checkout/CartTest.php
  • src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php
**/*.php

📄 CodeRabbit inference engine (AGENTS.md)

**/*.php: Use modern PHP 8.2+ syntax and features
Declare strict_types=1 in all PHP files
Follow the Sylius Coding Standard
Do not use deprecated features from PHP, Symfony, or Sylius
Use final for all classes, except entities and repositories
Use readonly for immutable services and value objects
Add type declarations for all properties, arguments, and return values
Use camelCase for variables and method names
Use SCREAMING_SNAKE_CASE for constants
Use fast returns instead of unnecessary nesting
Use trailing commas in multi-line arrays and argument lists
Order array keys alphabetically where applicable
Use PHPDoc only when necessary (e.g., @var Collection)
Group class elements in order: constants, properties, constructor, public, protected, private methods
Group getter and setter methods for the same properties together
Suffix interfaces with Interface and traits with Trait
Use use statements for all non-global classes
Sort use imports alphabetically and group by type (classes, functions, constants)

Files:

  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php
  • tests/Api/Shop/Checkout/CartTest.php
  • src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php
tests/**/*Test.php

📄 CodeRabbit inference engine (AGENTS.md)

Use PHPUnit for unit and functional testing

Files:

  • tests/Api/Shop/Checkout/CartTest.php
🧬 Code graph analysis (6)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php (2)
src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1)
  • UnprocessableCartException (18-27)
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (1)
  • __invoke (41-64)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (2)
src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1)
  • UnprocessableCartException (18-27)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
  • ProductVariantNotFoundException (18-27)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1)
  • __construct (20-26)
src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (1)
src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1)
  • UnprocessableCartException (18-27)
tests/Api/Shop/Checkout/CartTest.php (1)
tests/Api/JsonApiTestCase.php (2)
  • setUpDefaultPostHeaders (95-101)
  • requestPost (169-182)
src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)
  • __construct (20-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Packages / Get matrix
  • GitHub Check: End-to-end tests (MySQL) / Get matrix
  • GitHub Check: End-to-end tests (PostgreSQL) / Get matrix
  • GitHub Check: End-to-end tests (MariaDB) / Get matrix
  • GitHub Check: Frontend / Get matrix
🔇 Additional comments (6)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (2)

104-121: Good: dedicated HTTP-friendly exception asserted.

Using UnprocessableCartException aligns with 422 semantics for unprocessable POST.


89-102: Disregard this review comment; the handler checks the product variant before the cart.

The test is correct as written. The AddItemToCartHandler.__invoke() method checks the product variant at line 48, throws ProductVariantNotFoundException if null at lines 50-51, and only then checks the cart at line 55. Since the variant lookup happens first, the test will consistently throw the expected exception when the variant is not found, regardless of cart state. Stubbing the cart is unnecessary and adds noise.

Likely an incorrect or invalid review comment.

src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (1)

47-58: Correct HTTP semantics for error cases.

404 for missing user, 422 for missing cart, and 409 for occupied cart are appropriate replacements for generic exceptions.

src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1)

18-27: LGTM: focused 422 exception with stable message.

Final class, strict types, and concise constructor look good.

tests/Api/Shop/Checkout/CartTest.php (1)

639-650: Good coverage for non-existing cart → 422.

Assertion aligns with UnprocessableCartException message and status.

src/Sylius/Bundle/ApiBundle/Exception/ProductVariantNotFoundException.php (1)

18-27: LGTM! Clean exception implementation.

The exception class follows all coding guidelines and is consistent with the existing UnprocessableCartException pattern. The implementation correctly:

  • Uses final class modifier
  • Declares strict types
  • Provides proper type hints for all parameters
  • Uses trailing commas in multi-line parameter lists
  • Returns HTTP 422 (Unprocessable Entity) via the parent class, aligning with the PR objective to replace 500 errors with appropriate 4xx codes

The fixed error message clearly identifies the issue for API consumers.

@Rafikooo Rafikooo force-pushed the fix/api-cart-error-codes branch from 1e5acc3 to 7fe2023 Compare November 3, 2025 10:31
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/Api/Shop/Checkout/CartTest.php (1)

652-678: Critical mismatch between exception message and test expectation.

The test expects hydra:description to contain "does not exist" (line 677), but ProductVariantUnprocessableException (lines 20-26 of ProductVariantUnprocessableException.php) defines the message as "Product variant could not be processed." This mismatch will cause the test to fail.

Apply this diff to align the test with the actual exception message:

-        $this->assertStringContainsString('does not exist', $response['hydra:description']);
+        $this->assertStringContainsString('Product variant could not be processed', $response['hydra:description']);

Alternatively, if "does not exist" is the intended message, update the exception:

In ProductVariantUnprocessableException.php:

-        parent::__construct('Product variant could not be processed.', $previous, $code, $headers);
+        parent::__construct('Product variant does not exist.', $previous, $code, $headers);
🧹 Nitpick comments (1)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantUnprocessableException.php (1)

20-26: Consider a more specific error message for consistency.

The message "Product variant could not be processed." is less specific than the sibling exception UnprocessableCartException, which uses "Cart with given token has not been found." For consistency and clarity, consider a more specific message.

Apply this diff for better clarity and consistency with UnprocessableCartException:

-        parent::__construct('Product variant could not be processed.', $previous, $code, $headers);
+        parent::__construct('Product variant with given code has not been found.', $previous, $code, $headers);

This also resolves the test expectation mismatch flagged in tests/Api/Shop/Checkout/CartTest.php line 677.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e5acc3 and 7fe2023.

📒 Files selected for processing (7)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php (2 hunks)
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php (2 hunks)
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantUnprocessableException.php (1 hunks)
  • src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1 hunks)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (3 hunks)
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php (3 hunks)
  • tests/Api/Shop/Checkout/CartTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/BlameCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/BlameCartHandler.php
  • src/Sylius/Bundle/ApiBundle/CommandHandler/Cart/AddItemToCartHandler.php
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{php,yaml,yml,xml,twig}

📄 CodeRabbit inference engine (AGENTS.md)

Use 4 spaces for indentation in PHP, YAML, XML, and Twig files

Files:

  • tests/Api/Shop/Checkout/CartTest.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantUnprocessableException.php
tests/**/*Test.php

📄 CodeRabbit inference engine (AGENTS.md)

Use PHPUnit for unit and functional testing

Files:

  • tests/Api/Shop/Checkout/CartTest.php
**/*.php

📄 CodeRabbit inference engine (AGENTS.md)

**/*.php: Use modern PHP 8.2+ syntax and features
Declare strict_types=1 in all PHP files
Follow the Sylius Coding Standard
Do not use deprecated features from PHP, Symfony, or Sylius
Use final for all classes, except entities and repositories
Use readonly for immutable services and value objects
Add type declarations for all properties, arguments, and return values
Use camelCase for variables and method names
Use SCREAMING_SNAKE_CASE for constants
Use fast returns instead of unnecessary nesting
Use trailing commas in multi-line arrays and argument lists
Order array keys alphabetically where applicable
Use PHPDoc only when necessary (e.g., @var Collection)
Group class elements in order: constants, properties, constructor, public, protected, private methods
Group getter and setter methods for the same properties together
Suffix interfaces with Interface and traits with Trait
Use use statements for all non-global classes
Sort use imports alphabetically and group by type (classes, functions, constants)

Files:

  • tests/Api/Shop/Checkout/CartTest.php
  • src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php
  • src/Sylius/Bundle/ApiBundle/Exception/ProductVariantUnprocessableException.php
🧠 Learnings (1)
📚 Learning: 2025-09-01T12:06:56.917Z
Learnt from: CR
Repo: Sylius/Sylius PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-01T12:06:56.917Z
Learning: Applies to tests/**/*Api*.php : Use PHPUnit tests to validate API configuration and API responses

Applied to files:

  • tests/Api/Shop/Checkout/CartTest.php
🧬 Code graph analysis (3)
tests/Api/Shop/Checkout/CartTest.php (1)
tests/Api/JsonApiTestCase.php (2)
  • setUpDefaultPostHeaders (95-101)
  • requestPost (169-182)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (2)
src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1)
  • UnprocessableCartException (18-27)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantUnprocessableException.php (1)
  • ProductVariantUnprocessableException (18-27)
src/Sylius/Bundle/ApiBundle/Exception/ProductVariantUnprocessableException.php (1)
src/Sylius/Bundle/ApiBundle/Exception/UnprocessableCartException.php (1)
  • __construct (20-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Packages / Get matrix
  • GitHub Check: End-to-end tests (PostgreSQL) / Get matrix
  • GitHub Check: Frontend / Get matrix
  • GitHub Check: End-to-end tests (MariaDB) / Get matrix
  • GitHub Check: End-to-end tests (MySQL) / Get matrix
🔇 Additional comments (2)
src/Sylius/Bundle/ApiBundle/tests/CommandHandler/Cart/AddItemToCartHandlerTest.php (1)

28-29: LGTM! Exception expectations properly updated.

The test expectations have been correctly updated to use the new domain-specific HTTP exceptions (UnprocessableCartException and ProductVariantUnprocessableException) instead of generic InvalidArgumentException, aligning with the PR's goal of providing proper 4xx error codes.

Also applies to: 96-96, 115-115

tests/Api/Shop/Checkout/CartTest.php (1)

626-650: LGTM! Properly validates 422 response for non-existent cart.

This test correctly verifies that attempting to add an item to a non-existent cart returns HTTP 422 with the appropriate error message from UnprocessableCartException.

@NoResponseMate NoResponseMate merged commit 7f4092f into Sylius:2.1 Nov 3, 2025
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API APIs related issues and PRs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API] sylius_api_shop_order_order_item_post with not found order token throws 500, not 4**

2 participants