PHPackages                             rasuvaeff/yii3-api-problem - 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. rasuvaeff/yii3-api-problem

ActiveLibrary

rasuvaeff/yii3-api-problem
==========================

RFC 9457 Problem Details for Yii3 and any PSR-7/PSR-15 application

v1.0.0(1mo ago)06↓66.7%BSD-3-ClausePHPPHP 8.3 - 8.5CI passing

Since Jul 16Pushed 1w agoCompare

[ Source](https://github.com/rasuvaeff/yii3-api-problem)[ Packagist](https://packagist.org/packages/rasuvaeff/yii3-api-problem)[ Docs](https://github.com/rasuvaeff/yii3-api-problem)[ RSS](/packages/rasuvaeff-yii3-api-problem/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (1)Dependencies (15)Versions (3)Used By (0)

rasuvaeff/yii3-api-problem
==========================

[](#rasuvaeffyii3-api-problem)

[![Latest Stable Version](https://camo.githubusercontent.com/f19efd987b0751a361aaaec728d393e9c7e7feab4cbca82bf1c6d8fdce530a05/68747470733a2f2f706f7365722e707567782e6f72672f7261737576616566662f796969332d6170692d70726f626c656d2f762f737461626c65)](https://packagist.org/packages/rasuvaeff/yii3-api-problem)[![Total Downloads](https://camo.githubusercontent.com/b9f40c12ad071b11e42bc3ee6346793e0b8a8d18fda56add72f07684dfba0623/68747470733a2f2f706f7365722e707567782e6f72672f7261737576616566662f796969332d6170692d70726f626c656d2f646f776e6c6f616473)](https://packagist.org/packages/rasuvaeff/yii3-api-problem)[![Build](https://github.com/rasuvaeff/yii3-api-problem/actions/workflows/build.yml/badge.svg)](https://github.com/rasuvaeff/yii3-api-problem/actions/workflows/build.yml)[![Static analysis](https://github.com/rasuvaeff/yii3-api-problem/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/rasuvaeff/yii3-api-problem/actions/workflows/static-analysis.yml)[![Psalm level](https://camo.githubusercontent.com/e6fdf618686a271014a87c3a0752303d6ca246c0169bb090dcdf96202ad986e9/68747470733a2f2f73686570686572642e6465762f6769746875622f7261737576616566662f796969332d6170692d70726f626c656d2f6c6576656c2e737667)](https://shepherd.dev/github/rasuvaeff/yii3-api-problem)[![License](https://camo.githubusercontent.com/85a1e20f9786bbe50137cd176a5bdca0e084784fff273f9d02f415234ed41c0a/68747470733a2f2f706f7365722e707567782e6f72672f7261737576616566662f796969332d6170692d70726f626c656d2f6c6963656e7365)](LICENSE.md)[Русская версия](README.ru.md)

RFC 9457 Problem Details for Yii3 and any PSR-7/PSR-15 application. Use the value object directly, turn it into a hardened response, or catch exceptions with middleware that has explicit production and debug disclosure policies.

> Using an AI coding assistant? [llms.txt](llms.txt) is a compact API reference with the package rules and copy-ready examples.

Requirements
------------

[](#requirements)

- PHP 8.3-8.5.
- A PSR-7 implementation and PSR-17 response/stream factories.
- A PSR-15 stack only when using `ProblemDetailsMiddleware`.

Installation
------------

[](#installation)

```
composer require rasuvaeff/yii3-api-problem
```

The examples use `nyholm/psr7` as the PSR-7/17 implementation:

```
composer require nyholm/psr7
```

Usage
-----

[](#usage)

Create an RFC 9457 document in an action and return it as a PSR-7 response:

```
use Nyholm\Psr7\Factory\Psr17Factory;
use Rasuvaeff\Yii3ApiProblem\ProblemDetails;
use Rasuvaeff\Yii3ApiProblem\ProblemDetailsResponseFactory;

$problem = ProblemDetails::create(
    type: 'https://example.com/problems/insufficient-funds',
    title: 'Insufficient funds',
    status: 403,
    detail: 'The account balance is too low.',
    instance: '/transfers/42',
);

$psr17 = new Psr17Factory();
$response = (new ProblemDetailsResponseFactory($psr17, $psr17))
    ->toResponse($problem);
```

The response status comes from the problem. Its content type is always `application/problem+json`, and it always carries `X-Content-Type-Options: nosniff`.

### Value object

[](#value-object)

MethodPurpose`create(title, status, type, detail, instance, extensions)`Create a full problem document`fromStatus(status, title, type)`Create one using the HTTP reason phrase as the default title`withDetail(detail)`Return a copy with explanatory detail`withInstance(instance)`Return a copy with an occurrence identifier`withExtension(key, value)`Add or replace one extension member`withExtensions(extensions)`Replace all extension members`withInvalidParams(...params)`Add typed field-validation failures`toArray()` / `toJson(flags)`Serialize the problem document`type`, `title`, `status`, `detail`, and `instance` are reserved and cannot be used as extension names. Optional null members are omitted during serialization.

`InvalidParam` provides a stable shape for field validation failures:

```
use Rasuvaeff\Yii3ApiProblem\InvalidParam;

$problem = ProblemDetails::fromStatus(status: 422)->withInvalidParams(
    InvalidParam::create(name: 'email', reason: 'Invalid email address'),
    InvalidParam::create(name: 'age', reason: 'Must be at least 18'),
);
```

This produces the `invalid-params` extension shown in RFC 9457 examples. RFC 9457 permits extension members but does not standardize a universal validation error schema; consumers must opt into this package-defined shape.

### Transport headers

[](#transport-headers)

Pass headers when a problem needs HTTP metadata such as `Retry-After` or `WWW-Authenticate`:

```
$response = $responseFactory->toResponse(
    ProblemDetails::fromStatus(status: 429),
    headers: ['Retry-After' => '120'],
);
```

Header values may be strings or lists of strings. Caller headers cannot override the mandatory `application/problem+json` content type or `nosniff` policy.

### Throwing a problem

[](#throwing-a-problem)

An action may throw a problem intended for the client:

```
use Rasuvaeff\Yii3ApiProblem\ProblemDetails;
use Rasuvaeff\Yii3ApiProblem\ProblemDetailsException;

throw ProblemDetailsException::forProblem(
    details: ProblemDetails::create(
        title: 'Validation failed',
        status: 422,
    ),
    headers: ['Retry-After' => '60'],
);
```

`ProblemDetailsMiddleware` preserves this explicitly supplied document. In particular, an intentional `detail` is not removed in production.

### Exception middleware

[](#exception-middleware)

```
use Nyholm\Psr7\Factory\Psr17Factory;
use Rasuvaeff\Yii3ApiProblem\DefaultExceptionMapper;
use Rasuvaeff\Yii3ApiProblem\ProblemDetailsMiddleware;
use Rasuvaeff\Yii3ApiProblem\ProblemDetailsResponseFactory;

$psr17 = new Psr17Factory();
$middleware = new ProblemDetailsMiddleware(
    responseFactory: new ProblemDetailsResponseFactory($psr17, $psr17),
    exceptionMapper: new DefaultExceptionMapper(),
    debug: false,
);
```

Place it outside the application handler that may throw. Successful responses pass through unchanged. In production, ordinary exception messages and traces are never copied into the response. With `debug: true`, `detail` contains the exception message and the `trace` extension contains its stack trace. Never enable debug mode in production.

### Exception reporting

[](#exception-reporting)

The middleware can report the original exception before returning a safe response. Implement `ThrowableReporterInterface` as a small adapter to your logger, Sentry, or another observability system:

```
use Psr\Http\Message\ServerRequestInterface;
use Rasuvaeff\Yii3ApiProblem\ThrowableReporterInterface;

final readonly class SentryThrowableReporter implements ThrowableReporterInterface
{
    public function report(Throwable $throwable, ServerRequestInterface $request): void
    {
        Sentry\captureException($throwable);
    }
}

$middleware = new ProblemDetailsMiddleware(
    responseFactory: $responseFactory,
    exceptionMapper: $mapper,
    throwableReporter: new SentryThrowableReporter(),
);
```

The reporter receives both generic exceptions and `ProblemDetailsException`, is not called for successful responses, and must not throw.

The default mapper handles these cases:

ExceptionResult`ProblemDetailsException`Its enclosed documentConfigured exact exception classConfigured type, title, and status`InvalidArgumentException`400 Bad Request`RuntimeException`500 Internal Server ErrorAny other `Throwable``null`; middleware falls back to generic 500Configured entries match the exact class, not parent classes or interfaces:

```
$mapper = new DefaultExceptionMapper(exceptionMap: [
    App\Domain\UserNotFoundException::class => [
        'type' => 'https://example.com/problems/user-not-found',
        'title' => 'User not found',
        'status' => 404,
    ],
]);
```

Implement `ExceptionMapperInterface` when mapping needs domain-specific logic.

### Yii3 configuration

[](#yii3-configuration)

The config plugin binds `ProblemDetailsResponseFactoryInterface`, the concrete `DefaultExceptionMapper`, and `ProblemDetailsMiddleware`. It deliberately does not bind `ExceptionMapperInterface` or `ThrowableReporterInterface`, because the application owns those replaceable choices.

Default params:

```
return [
    'rasuvaeff/yii3-api-problem' => [
        'debug' => false,
        'use_default_mapper' => true,
        'exception_map' => [],
    ],
];
```

Your PSR-17 implementation must provide `ResponseFactoryInterface` and `StreamFactoryInterface` in the container. Override the middleware definition when supplying a custom mapper, `CorrelationIdProvider`, or reporter.

### Correlation ID

[](#correlation-id)

Implement this package's small `CorrelationIdProvider` interface and pass it to the middleware. A non-null ID becomes the problem `instance`:

```
use Rasuvaeff\Yii3ApiProblem\CorrelationIdProvider;

final readonly class ApiProblemCorrelationIdProvider implements CorrelationIdProvider
{
    public function __construct(
        private Rasuvaeff\Yii3CorrelationId\CorrelationIdProvider $provider,
    ) {}

    public function getCorrelationId(): ?string
    {
        return $this->provider->tryGet();
    }
}
```

The adapter keeps `rasuvaeff/yii3-correlation-id` optional.

When to use which
-----------------

[](#when-to-use-which)

Use this package when you want a small RFC 9457 value object plus a configurable exception mapper, typed validation extension, transport headers, exception reporting, production/debug disclosure policy, correlation ID integration, and Yii3 config-plugin wiring.

Use [`crell/api-problem`](https://packagist.org/packages/crell/api-problem) when you need its mature generic-PHP ecosystem, XML serialization, or its existing PSR-7/15/17 integration. It is an established package; this library is an opinionated Yii3-oriented alternative, not a claim that the generic niche is empty.

If `yiisoft/error-handler` already formats every exception in your application, use one error formatting path. This middleware must sit outside a throwing handler; it cannot reformat a response already produced by another error handler.

Security
--------

[](#security)

- Keep `debug` false in production. Ordinary exception messages and stack traces are considered sensitive.
- Treat extension values as response data. JSON encoding prevents structural JSON injection but does not make credentials or personal data safe to expose.
- Problem type URIs are identifiers, not automatically fetched documentation.
- `ProblemDetailsException` is an explicit disclosure boundary: only throw it with client-safe `detail`, extensions, and headers.
- Reporter implementations must not throw and must redact sensitive request data before sending it to third-party telemetry.

Examples
--------

[](#examples)

See [examples/](examples/) for executable scripts covering manual responses, exceptions, typed validation extensions, middleware setup, custom mappings, reporting, and transport headers.

Development
-----------

[](#development)

```
composer build
composer test
composer psalm
composer mutation
composer bench
```

PHP and Composer are run through Docker in this repository; the equivalent Make targets are `make build`, `make test`, `make psalm`, `make mutation`, and `make bench`.

License
-------

[](#license)

The package is released under the [BSD 3-Clause License](LICENSE.md).

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance95

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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

46d ago

### Community

Maintainers

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

---

Top Contributors

[![rasuvaeff](https://avatars.githubusercontent.com/u/1352718?v=4)](https://github.com/rasuvaeff "rasuvaeff (12 commits)")

---

Tags

api-errorsmiddlewarephpproblem-detailspsr-15psr-7rfc-9457yii3yii3-extensionsmiddlewarepsr-15problem detailsyii3rfc-9457

###  Code Quality

Static AnalysisPsalm, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/rasuvaeff-yii3-api-problem/health.svg)

```
[![Health](https://phpackages.com/badges/rasuvaeff-yii3-api-problem/health.svg)](https://phpackages.com/packages/rasuvaeff-yii3-api-problem)
```

###  Alternatives

[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[cakephp/cakephp

The CakePHP framework

8.9k20.4M1.9k](/packages/cakephp-cakephp)[typo3/cms-core

TYPO3 CMS Core

3714.0M5.8k](/packages/typo3-cms-core)[mcp/sdk

Model Context Protocol SDK for Client and Server applications in PHP

1.6k3.0M157](/packages/mcp-sdk)[tempest/framework

The PHP framework that gets out of your way.

2.3k42.4k21](/packages/tempest-framework)[cakephp/authentication

Authentication plugin for CakePHP

1184.6M126](/packages/cakephp-authentication)

PHPackages © 2026

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