PHPackages                             methorz/http-problem-details - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. methorz/http-problem-details

ActiveLibrary[HTTP &amp; Networking](/categories/http)

methorz/http-problem-details
============================

PSR-15 error handling middleware with RFC 7807 Problem Details support

v1.0.0(5mo ago)050MITPHPPHP ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0CI passing

Since Dec 1Pushed 4mo agoCompare

[ Source](https://github.com/MethorZ/http-problem-details)[ Packagist](https://packagist.org/packages/methorz/http-problem-details)[ RSS](/packages/methorz-http-problem-details/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (11)Versions (2)Used By (0)

MethorZ Error Handler Middleware
================================

[](#methorz-error-handler-middleware)

**Comprehensive error handling middleware for PSR-15 applications with RFC 7807 Problem Details support**

[![CI](https://github.com/MethorZ/http-problem-details/actions/workflows/ci.yml/badge.svg)](https://github.com/MethorZ/http-problem-details/actions/workflows/ci.yml)[![codecov](https://camo.githubusercontent.com/7cb67011805b3aa0f4a460c110a9523d0c95621a8541888486e2066701fd143a/68747470733a2f2f636f6465636f762e696f2f67682f4d6574686f725a2f687474702d70726f626c656d2d64657461696c732f67726170682f62616467652e737667)](https://codecov.io/gh/MethorZ/http-problem-details)[![PHPStan](https://camo.githubusercontent.com/1bc07920f0d36e55c17e1d38b1caa132cc605f51a82b388c962870b9a747b898/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230392d627269676874677265656e2e737667)](https://phpstan.org/)[![PHP Version](https://camo.githubusercontent.com/c9f64f714c636ba27a3bba6dfd52f98426832db1262747efa54b212d16943651/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e322d626c7565)](https://php.net)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE)

Production-ready error handling with RFC 7807 Problem Details, environment-aware formatting, automatic logging, and developer-friendly stack traces. Zero configuration, works out-of-the-box.

---

✨ Features
----------

[](#-features)

- 📋 **RFC 7807 Compliance** - Standardized error responses (Problem Details)
- 🔍 **Environment-Aware** - Stack traces in dev, sanitized messages in production
- 📝 **Automatic Logging** - PSR-3 logger integration with context
- 🎯 **Custom Exception Mapping** - Map exceptions to HTTP status codes
- 🔗 **Exception Chaining** - Captures and formats previous exception details
- 💡 **Developer-Friendly** - Detailed debugging info in development mode
- 🌍 **Production-Safe** - No sensitive data leaks in production
- 🎨 **Framework Agnostic** - Works with any PSR-15 application

---

📦 Installation
--------------

[](#-installation)

```
composer require methorz/http-problem-details
```

---

🚀 Quick Start
-------------

[](#-quick-start)

### **Basic Usage**

[](#basic-usage)

```
use MethorZ\ProblemDetails\Middleware\ErrorHandlerMiddleware;
use Nyholm\Psr7\Factory\Psr17Factory;

$middleware = new ErrorHandlerMiddleware(
    new Psr17Factory()
);

// Add to middleware pipeline (first!)
$app->pipe($middleware);
```

**Production Response** (500 Internal Server Error):

```
{
  "type": "about:blank",
  "title": "Internal Server Error",
  "status": 500,
  "detail": "An error occurred"
}
```

**Development Response** (with stack trace):

```
{
  "type": "about:blank",
  "title": "Internal Server Error",
  "status": 500,
  "detail": "Division by zero",
  "trace": "#0 /path/to/file.php(42): calculate()...",
  "file": "/path/to/file.php",
  "line": 42,
  "request_method": "POST",
  "request_uri": "https://api.example.com/calculate",
  "exception_class": "DivisionByZeroError"
}
```

---

📖 Detailed Usage
----------------

[](#-detailed-usage)

### **With Logger Integration**

[](#with-logger-integration)

```
use MethorZ\ProblemDetails\Middleware\ErrorHandlerMiddleware;
use Nyholm\Psr7\Factory\Psr17Factory;
use Monolog\Logger;

$logger = new Logger('app');

$middleware = new ErrorHandlerMiddleware(
    new Psr17Factory(),
    $logger // PSR-3 logger
);
```

**Logged Context**:

```
[2024-11-26 10:30:00] app.ERROR: Exception caught: User not found {
    "exception_class": "App\\Exception\\NotFoundException",
    "exception_message": "User not found",
    "exception_code": 0,
    "exception_file": "/app/src/Service/UserService.php",
    "exception_line": 42,
    "request_method": "GET",
    "request_uri": "https://api.example.com/users/123"
}

```

### **Development vs Production Mode**

[](#development-vs-production-mode)

```
// Development: Include stack traces and debug info
$devMiddleware = new ErrorHandlerMiddleware(
    $responseFactory,
    $logger,
    isDevelopment: true // ← Enable debug mode
);

// Production: Sanitized error messages
$prodMiddleware = new ErrorHandlerMiddleware(
    $responseFactory,
    $logger,
    isDevelopment: false // ← Production safe
);
```

### **Custom Exception Status Mapping**

[](#custom-exception-status-mapping)

```
use App\Exception\NotFoundException;
use App\Exception\ValidationException;

$middleware = new ErrorHandlerMiddleware(
    $responseFactory,
    $logger,
    exceptionStatusMap: [
        NotFoundException::class => 404,
        ValidationException::class => 422,
        \InvalidArgumentException::class => 400,
    ]
);
```

**Before**:

- `NotFoundException` → 500 Internal Server Error ❌

**After**:

- `NotFoundException` → 404 Not Found ✅
- `ValidationException` → 422 Unprocessable Entity ✅

---

🎯 RFC 7807 Problem Details
--------------------------

[](#-rfc-7807-problem-details)

### **Building Custom Problem Details**

[](#building-custom-problem-details)

```
use MethorZ\ProblemDetails\Response\ProblemDetails;
use Nyholm\Psr7\Response;

$problem = ProblemDetails::create(404, 'Not Found')
    ->withType('https://api.example.com/problems/user-not-found')
    ->withDetail('User with ID 123 does not exist')
    ->withInstance('/api/users/123')
    ->withAdditional('user_id', 123);

$response = $problem->toResponse(new Response());
```

**Response**:

```
{
  "type": "https://api.example.com/problems/user-not-found",
  "title": "Not Found",
  "status": 404,
  "detail": "User with ID 123 does not exist",
  "instance": "/api/users/123",
  "user_id": 123
}
```

### **Creating from Exception**

[](#creating-from-exception)

```
$exception = new NotFoundException('User not found');

// Production mode
$problem = ProblemDetails::fromException($exception, includeTrace: false);

// Development mode
$problem = ProblemDetails::fromException($exception, includeTrace: true);
```

---

🔍 Environment-Aware Behavior
----------------------------

[](#-environment-aware-behavior)

### **Development Mode** (`isDevelopment: true`)

[](#development-mode-isdevelopment-true)

**Response includes**:

- ✅ Full exception message
- ✅ Stack trace
- ✅ File path and line number
- ✅ Exception class name
- ✅ Request method and URI
- ✅ Previous exception chain

**Use when**: Local development, staging, testing

### **Production Mode** (`isDevelopment: false`)

[](#production-mode-isdevelopment-false)

**Response includes**:

- ✅ HTTP status code
- ✅ Generic title
- ✅ Exception message (if safe)
- ❌ NO stack traces
- ❌ NO file paths
- ❌ NO internal details

**Use when**: Production, public APIs

---

📊 HTTP Status Code Mapping
--------------------------

[](#-http-status-code-mapping)

Exception TypeStatus CodeLog LevelClient errors (4xx)400-499`warning`Server errors (5xx)500-599`error`**Supported Status Codes**:

```
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
405 Method Not Allowed
408 Request Timeout
409 Conflict
422 Unprocessable Entity
429 Too Many Requests
500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout

```

---

🔗 Exception Chaining
--------------------

[](#-exception-chaining)

Automatically captures and formats exception chains:

```
try {
    $db->connect(); // Throws PDOException
} catch (PDOException $e) {
    throw new DatabaseException('Failed to connect', 0, $e); // Wraps PDOException
}
```

**Development Response** (with `previous_exception`):

```
{
  "status": 500,
  "title": "Internal Server Error",
  "detail": "Failed to connect",
  "trace": "...",
  "previous_exception": {
    "class": "PDOException",
    "message": "SQLSTATE[HY000] [2002] Connection refused",
    "file": "/app/src/Database.php",
    "line": 25
  }
}
```

---

🧪 Testing
---------

[](#-testing)

```
# Run tests
composer test

# Static analysis
composer analyze

# Code style
composer cs-check
composer cs-fix
```

**Test Coverage**: 21 tests, 59 assertions, 100% passing

---

🛠️ Use Cases
------------

[](#️-use-cases)

### **1. REST API Error Handling**

[](#1-rest-api-error-handling)

```
// Global error handler (first middleware)
$app->pipe(new ErrorHandlerMiddleware(
    $responseFactory,
    $logger,
    isDevelopment: $_ENV['APP_ENV'] === 'development'
));

// All uncaught exceptions become RFC 7807 responses
```

### **2. Custom Application Exceptions**

[](#2-custom-application-exceptions)

```
namespace App\Exception;

class UserNotFoundException extends \RuntimeException
{
    public function getStatusCode(): int
    {
        return 404; // ← Automatically used by middleware
    }
}
```

### **3. Validation Error Responses**

[](#3-validation-error-responses)

```
$middleware = new ErrorHandlerMiddleware(
    $responseFactory,
    $logger,
    exceptionStatusMap: [
        ValidationException::class => 422,
    ]
);

throw new ValidationException('Email is required');
// → 422 Unprocessable Entity with Problem Details
```

### **4. Microservices Error Consistency**

[](#4-microservices-error-consistency)

All services return the same RFC 7807 format:

```
{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404,
  "detail": "Resource not found"
}
```

---

🔧 Configuration Examples
------------------------

[](#-configuration-examples)

### **Mezzio / Laminas**

[](#mezzio--laminas)

```
// config/autoload/middleware.global.php
use MethorZ\ProblemDetails\Middleware\ErrorHandlerMiddleware;

return [
    'dependencies' => [
        'factories' => [
            ErrorHandlerMiddleware::class => function ($container): ErrorHandlerMiddleware {
                return new ErrorHandlerMiddleware(
                    $container->get(ResponseFactoryInterface::class),
                    $container->get(LoggerInterface::class),
                    isDevelopment: $_ENV['APP_ENV'] === 'development',
                    exceptionStatusMap: [
                        NotFoundException::class => 404,
                        ValidationException::class => 422,
                    ],
                );
            },
        ],
    ],
];

// config/pipeline.php
$app->pipe(ErrorHandlerMiddleware::class); // FIRST middleware!
```

### **Slim Framework**

[](#slim-framework)

```
use MethorZ\ProblemDetails\Middleware\ErrorHandlerMiddleware;

$app->add(new ErrorHandlerMiddleware(
    $responseFactory,
    $logger,
    isDevelopment: $_ENV['DEBUG'] === 'true'
));
```

---

📚 Resources
-----------

[](#-resources)

- [RFC 7807: Problem Details for HTTP APIs](https://tools.ietf.org/html/rfc7807)
- [PSR-3: Logger Interface](https://www.php-fig.org/psr/psr-3/)
- [PSR-15: HTTP Server Middleware](https://www.php-fig.org/psr/psr-15/)

---

🔗 Related Packages
------------------

[](#-related-packages)

This package is part of the MethorZ HTTP middleware ecosystem:

PackageDescription**[methorz/http-dto](https://github.com/methorz/http-dto)**Automatic HTTP ↔ DTO conversion with validation**[methorz/http-problem-details](https://github.com/methorz/http-problem-details)**RFC 7807 error handling (this package)**[methorz/http-cache-middleware](https://github.com/methorz/http-cache-middleware)**HTTP caching with ETag support**[methorz/http-request-logger](https://github.com/methorz/http-request-logger)**Structured logging with request tracking**[methorz/openapi-generator](https://github.com/methorz/openapi-generator)**Automatic OpenAPI spec generationThese packages work together seamlessly in PSR-15 applications.

---

💡 Best Practices
----------------

[](#-best-practices)

### **DO**

[](#do)

- ✅ Place error middleware FIRST in pipeline
- ✅ Use `isDevelopment` based on environment variable
- ✅ Map domain exceptions to appropriate HTTP status codes
- ✅ Log exceptions with context for debugging
- ✅ Use PSR-3 logger for centralized log management

### **DON'T**

[](#dont)

- ❌ Don't expose stack traces in production (`isDevelopment: false`)
- ❌ Don't return 500 for client errors (use 4xx instead)
- ❌ Don't log sensitive data (passwords, tokens) in error context
- ❌ Don't catch errors before error middleware (let it handle them)

---

🔒 Security Considerations
-------------------------

[](#-security-considerations)

### **Sensitive Data**

[](#sensitive-data)

- ✅ Production mode hides file paths and stack traces
- ✅ Exception messages are still included (ensure they're safe!)
- ✅ Logger context can be filtered/redacted
- ❌ Don't include passwords, tokens, or PII in exception messages

### **Information Disclosure**

[](#information-disclosure)

```
// ❌ BAD: Leaks sensitive info
throw new Exception("DB connection failed: password='secret123'");

// ✅ GOOD: Generic message
throw new DatabaseException("Failed to connect to database");
```

---

📄 License
---------

[](#-license)

MIT License. See [LICENSE](LICENSE) for details.

---

🤝 Contributing
--------------

[](#-contributing)

Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

---

🔗 Links
-------

[](#-links)

- [Changelog](CHANGELOG.md)
- [Contributing](CONTRIBUTING.md)
- [Security](SECURITY.md)
- [Issues](https://github.com/MethorZ/http-problem-details/issues)

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance73

Regular maintenance activity

Popularity8

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

159d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b0233a9072fdc1746031fd96b487fce9b0d5f55c0124b70fc51ac2bb833bb906?d=identicon)[MethorZ](/maintainers/MethorZ)

---

Tags

composererror-handlingexception-handlerframework-agnosticloggingmiddlewarepackagistphpphp8problem-detailspsr-15psr-3rfc-7807httpmiddlewarepsr-15error-handlerproblem detailsrfc 7807exception handler

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/methorz-http-problem-details/health.svg)

```
[![Health](https://phpackages.com/badges/methorz-http-problem-details/health.svg)](https://phpackages.com/packages/methorz-http-problem-details)
```

###  Alternatives

[mezzio/mezzio

PSR-15 Middleware Microframework

3883.6M97](/packages/mezzio-mezzio)[mezzio/mezzio-authentication-oauth2

OAuth2 (server) authentication middleware for Mezzio and PSR-7 applications.

28483.0k2](/packages/mezzio-mezzio-authentication-oauth2)[mezzio/mezzio-authentication

Authentication middleware for Mezzio and PSR-7 applications

121.6M26](/packages/mezzio-mezzio-authentication)[middlewares/utils

Common utils for PSR-15 middleware packages

503.4M93](/packages/middlewares-utils)[laminas/laminas-stratigility

PSR-7 middleware foundation for building and dispatching middleware pipelines

586.6M81](/packages/laminas-laminas-stratigility)[sunrise/http-router

A powerful solution as the foundation of your project.

16249.8k10](/packages/sunrise-http-router)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
