Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Api Problem Laravel Package

phpro/api-problem

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require phpro/api-problem
    
  2. First use case: Throw an ApiProblemException with a built-in problem type (e.g., NotFoundProblem) in your Laravel controller or service:

    use Phpro\ApiProblem\Exception\ApiProblemException;
    use Phpro\ApiProblem\Http\NotFoundProblem;
    
    throw new ApiProblemException(new NotFoundProblem('Resource not found'));
    
  3. Handle exceptions in Laravel: Use Laravel’s exception handler (app/Exceptions/Handler.php) to convert ApiProblemException into a JSON response:

    public function render($request, Throwable $exception)
    {
        if ($exception instanceof ApiProblemException) {
            return response()->json($exception->getProblem()->toArray(), $exception->getProblem()->getStatus());
        }
        return parent::render($request, $exception);
    }
    
  4. Test locally: Trigger the exception in a route or controller and verify the response matches RFC7807 format:

    {
        "status": 404,
        "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
        "title": "Not found",
        "detail": "Resource not found"
    }
    

Implementation Patterns

Core Workflows

  1. Standard Error Responses: Replace generic Laravel exceptions (e.g., HttpResponseException) with ApiProblemException for consistent API responses:

    // Before
    throw new HttpResponseException(response()->json(['error' => 'Not found'], 404));
    
    // After
    throw new ApiProblemException(new NotFoundProblem('Resource not found'));
    
  2. Validation Errors: Use ValidationApiProblem for Symfony Validator errors (requires symfony/validator):

    use Phpro\ApiProblem\Http\ValidationApiProblem;
    use Symfony\Component\Validator\ConstraintViolationList;
    
    $violations = $validator->validate($request->all());
    throw new ApiProblemException(new ValidationApiProblem($violations));
    
  3. Custom Problems: Extend HttpApiProblem for domain-specific errors:

    class PaymentFailedProblem extends HttpApiProblem
    {
        public function __construct(string $message, ?int $status = 400)
        {
            parent::__construct($status, [
                'detail' => $message,
                'type' => 'https://example.com/problems/payment-failed'
            ]);
        }
    }
    
  4. Debug Context: Implement DebuggableApiProblemInterface to include stack traces in development:

    class DebugProblem implements DebuggableApiProblemInterface
    {
        public function toDebuggableArray(): array
        {
            return array_merge(
                $this->toArray(),
                ['trace' => debug_backtrace()]
            );
        }
    }
    

Integration Tips

  • Middleware: Create middleware to catch ApiProblemException and format responses globally.
  • Service Layer: Centralize error handling in services to avoid duplication in controllers.
  • Testing: Use ApiProblemException in unit tests to assert response formats:
    $this->expectException(ApiProblemException::class);
    $this->expectExceptionMessage('Resource not found');
    

Gotchas and Tips

Pitfalls

  1. Exception Handling:

    • Laravel’s default handler won’t automatically convert ApiProblemException to JSON. Override render() in Handler.php as shown in Getting Started.
    • Tip: Use instanceof checks to avoid masking other exceptions.
  2. Debug Information:

    • ExceptionApiProblem only includes debug data (e.g., stack traces) in debug mode (Laravel’s APP_DEBUG=true). Disable in production to avoid leaking sensitive data.
    • Tip: Use environment variables to toggle debug details:
      if (app()->environment('local')) {
          $problem = new ExceptionApiProblem($exception);
      } else {
          $problem = new HttpApiProblem(500, ['detail' => $exception->getMessage()]);
      }
      
  3. HTTP Status Codes:

    • Custom problems must explicitly set a valid HTTP status code (e.g., 400, 500). Invalid codes may cause issues with Laravel’s response handling.
    • Tip: Extend HttpApiProblem to enforce valid codes:
      parent::__construct($this->validateStatusCode($status), $data);
      
  4. ValidationApiProblem:

    • Requires symfony/validator (≥4.1). Install via Composer:
      composer require symfony/validator
      
    • Tip: Cache the validator instance to avoid re-instantiating it for each request.
  5. Performance:

    • Avoid creating ApiProblem objects in tight loops (e.g., batch processing). Reuse instances where possible.
    • Tip: Use static factories for common problems:
      class ProblemFactory {
          public static function notFound(string $detail): NotFoundProblem {
              return new NotFoundProblem($detail);
          }
      }
      

Debugging

  • Missing Responses:

    • Verify ApiProblemException is caught in Handler.php. Check for typos in exception class names.
    • Debug: Temporarily log exceptions in render() to confirm they’re being processed:
      Log::debug('Caught exception:', ['exception' => $exception]);
      
  • Invalid JSON:

    • Ensure toArray() returns a valid JSON-serializable structure. Use json_encode($problem->toArray()) to test.
    • Tip: Add a helper method to validate output:
      public function isValid(): bool {
          return json_encode($this->toArray()) !== false;
      }
      
  • Debug Data Leaks:

    • Confirm APP_DEBUG is false in production. Use Laravel’s config('app.debug') to check dynamically:
      if (config('app.debug')) {
          $problem = new ExceptionApiProblem($exception);
      }
      

Extension Points

  1. Custom Problem Types:

    • Add new problems by extending HttpApiProblem or implementing ApiProblemInterface. Place them in app/ApiProblem for autoloading.
    • Example: Create a RateLimitProblem for API rate limiting.
  2. Global Problem Modifiers:

    • Use Laravel’s service provider to modify problems globally:
      public function boot() {
          ApiProblemException::macro('addContext', function ($context) {
              $this->getProblem()->addProperty('context', $context);
              return $this;
          });
      }
      
    • Usage:
      throw (new ApiProblemException(new NotFoundProblem('Not found')))
          ->addContext(['user_id' => auth()->id()]);
      
  3. Localization:

    • Override problem titles/details using Laravel’s translation system. Extend HttpApiProblem to use __():
      parent::__construct(404, [
          'title' => __('errors.not_found.title'),
          'detail' => __('errors.not_found.detail', ['id' => $id])
      ]);
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor