承接 tiny-blocks/http-middleware-error 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

tiny-blocks/http-middleware-error

Composer 安装命令:

composer require tiny-blocks/http-middleware-error

包简介

PSR-15 middleware that maps thrown exceptions to structured JSON error responses with optional logging.

README 文档

README

License

Overview

Provides a PSR-15 middleware that captures exceptions thrown by downstream handlers and translates them into structured JSON error responses. Each consumer declares an ExceptionMapping, a class whose mappings() method returns an ExceptionMappingTable that turns each known exception into a MappedError (machine-readable code, HTTP status between 400 and 599, human-readable message, optional headers). The consumer declares only the rules it owns, and the middleware composes the tables of every configured mapping into a single first-match-wins lookup, so neither the consumer nor the middleware repeats the composition. Unmapped exceptions either short-circuit to a generic 500 fallback or rethrow, depending on the builder configuration.

The library integrates with tiny-blocks/http-middleware-correlation-id to enrich every log entry with the request's correlation identifier when one is present on the request attributes, so error logs can be grouped across services without any extra plumbing in the consumer's log calls.

Installation

composer require tiny-blocks/http-middleware-error

How to use

Declaring a mapping

A consumer declares the rules it owns by implementing ExceptionMapping. The mappings() method returns an ExceptionMappingTable built once, so the same table is reused on every request rather than rebuilt per exception. Rules are evaluated in registration order, and the first match wins. Exact-class, listed-class, and subclass matches cover the common cases.

<?php

declare(strict_types=1);

use DomainException;
use InvalidArgumentException;
use RuntimeException;
use TinyBlocks\HttpMiddlewareError\ExceptionMapping;
use TinyBlocks\HttpMiddlewareError\ExceptionMappingTable;

final readonly class ApplicationExceptionMapping implements ExceptionMapping
{
    public function mappings(): ExceptionMappingTable
    {
        return ExceptionMappingTable::create()
            ->when(exceptionClass: InvalidArgumentException::class)
            ->mapsTo(code: 'INVALID_INPUT', status: 400, message: 'The request payload is invalid.')
            ->whenAny(exceptionClasses: [DomainException::class, RuntimeException::class])
            ->mapsTo(code: 'BUSINESS_FAILURE', status: 422, message: 'The operation could not be completed.')
            ->whenSubclassOf(baseException: RuntimeException::class)
            ->mapsTo(code: 'RUNTIME_FAMILY', status: 500, message: 'A runtime error occurred.');
    }
}

Register the mapping on the middleware and add it to the PSR-15 pipeline.

<?php

declare(strict_types=1);

use TinyBlocks\HttpMiddlewareError\ErrorMiddleware;

# Build the middleware with the declared mapping.
$middleware = ErrorMiddleware::create()
    ->withMapping(mapping: new ApplicationExceptionMapping())
    ->build();

Composing multiple mappings

When several verticals each own a mapping (for example, a write side and a read side), pass them all to withMappings. The middleware composes them into a single first-match-wins lookup, evaluating the mappings in the order given, so the consumer never writes the composition by hand.

<?php

declare(strict_types=1);

use TinyBlocks\HttpMiddlewareError\ErrorMiddleware;

# The mappings are supplied by the consumer.
$write = new WriteExceptionMapping();
$read = new ReadExceptionMapping();

# Compose both mappings under one middleware.
$middleware = ErrorMiddleware::create()
    ->withMappings($write, $read)
    ->build();

Resolving the response from the exception

Builds the MappedError from the matched exception when the response depends on runtime state (for example, when the exception carries fields that should be exposed to the client). The closure receives the matched throwable and returns a MappedError built from it.

<?php

declare(strict_types=1);

use RuntimeException;
use Throwable;
use TinyBlocks\HttpMiddlewareError\ExceptionMapping;
use TinyBlocks\HttpMiddlewareError\ExceptionMappingTable;
use TinyBlocks\HttpMiddlewareError\MappedError;

final readonly class GatewayExceptionMapping implements ExceptionMapping
{
    public function mappings(): ExceptionMappingTable
    {
        return ExceptionMappingTable::create()
            ->when(exceptionClass: RuntimeException::class)
            ->resolvesWith(
                resolver: fn(Throwable $exception): MappedError => new MappedError(
                    code: 'GATEWAY_UNAVAILABLE',
                    status: 502,
                    message: $exception->getMessage()
                )
            );
    }
}

Logging and displaying error details

Enables structured error logging and the optional inclusion of exception details in the response body. The defaults are silent and secure: nothing is logged and no stack traces are returned to the client.

<?php

declare(strict_types=1);

use Psr\Log\LoggerInterface;
use TinyBlocks\HttpMiddlewareError\ErrorHandlingSettings;
use TinyBlocks\HttpMiddlewareError\ErrorMiddleware;
use TinyBlocks\HttpMiddlewareError\ExceptionMapping;

# The logger and the mapping are supplied by the consumer.
$logger = /** @var LoggerInterface */ null;
$mapping = /** @var ExceptionMapping */ null;

# Enable error logging with full details, but keep stack traces out of the response.
$middleware = ErrorMiddleware::create()
    ->withLogger(logger: $logger)
    ->withMapping(mapping: $mapping)
    ->withSettings(settings: ErrorHandlingSettings::from(
        logErrors: true,
        logErrorDetails: true,
        displayErrorDetails: false
    ))
    ->build();

Disabling the fallback for unmapped exceptions

Forces unmapped exceptions to propagate to the outer handler instead of returning the generic 500 fallback. Useful when a higher-level error boundary should observe the original throwable.

<?php

declare(strict_types=1);

use TinyBlocks\HttpMiddlewareError\ErrorMiddleware;
use TinyBlocks\HttpMiddlewareError\ExceptionMapping;

# The mapping is supplied by the consumer.
$mapping = /** @var ExceptionMapping */ null;

# Disable the fallback so that unmapped exceptions rethrow.
$middleware = ErrorMiddleware::create()
    ->withMapping(mapping: $mapping)
    ->withFallbackOnUnmapped(false)
    ->build();

License

Http Middleware Error is licensed under MIT.

Contributing

Please follow the contributing guidelines to contribute to the project.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-26