定制 dev-toolbelt/jsend-payload 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

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

dev-toolbelt/jsend-payload

Composer 安装命令:

composer require dev-toolbelt/jsend-payload

包简介

A framework-agnostic PHP library for building standardized JSend API responses with PSR-7 support

README 文档

README

CI Coverage Latest Stable Version Total Downloads License PHP Version

A framework-agnostic PHP library for building standardized API responses following the JSend specification. Provides a simple trait that can be mixed into any controller or handler to generate consistent JSON responses with PSR-7 support.

Features

  • Framework Independence - Works with Laravel, Symfony, Slim, Mezzio, or any PSR-7 compatible framework
  • JSend Compliant - Follows the JSend specification for standardized API responses
  • PSR-7 Support - Returns Psr\Http\Message\ResponseInterface for maximum interoperability
  • Type-Safe HTTP Codes - Uses enums for HTTP status codes, preventing invalid values
  • Common Response Helpers - Pre-built methods for validation errors, not found, empty payloads, and more
  • Zero Configuration - Just use the trait and start returning standardized responses

Requirements

  • PHP 8.1 or higher

Installation

composer require dev-toolbelt/jsend-payload

Quick Start

Add the AnswerTrait to your controller and start returning standardized responses:

<?php

use DevToolbelt\JsendPayload\AnswerTrait;
use Psr\Http\Message\ResponseInterface;

class UserController
{
    use AnswerTrait;

    public function show(string $id): ResponseInterface
    {
        $user = $this->userRepository->find($id);

        if (!$user) {
            return $this->answerRecordNotFound();
        }

        return $this->answerSuccess($user);
    }
}

Understanding JSend

JSend is a specification for a simple, standardized format for JSON responses from web servers. It defines three response types:

Status Description When to Use
success All went well, data is returned Successful GET, POST, PUT, DELETE operations
fail Problem with submitted data or call conditions Validation errors, missing required fields
error Server error occurred Exceptions, database failures, unexpected errors

Usage

Success Responses

Use for successful operations that return data:

// Returns: {"status": "success", "data": {"id": 1, "name": "John"}}
return $this->answerSuccess(['id' => 1, 'name' => 'John']);

// With custom HTTP status code
use DevToolbelt\Enums\Http\HttpStatusCode;

return $this->answerSuccess($createdUser, HttpStatusCode::CREATED);

Fail Responses

Use when there's a problem with the data submitted:

// Returns: {"status": "fail", "data": [{"field": "email", "error": "required"}]}
return $this->answerFail([
    ['field' => 'email', 'error' => 'required', 'message' => 'Email is required']
]);

Error Responses

Use for server-side errors:

// Returns: {"status": "error", "message": "Database connection failed"}
return $this->answerError('Database connection failed');

// With additional data
return $this->answerError(
    'Validation failed',
    HttpStatusCode::UNPROCESSABLE_ENTITY,
    ['traceId' => 'abc-123']
);

No Content Response

Use when operation succeeds but there's no data to return:

// Returns: {"status": "success", "data": null}
return $this->answerNoContent();

Helper Methods

The trait includes convenient methods for common API scenarios:

Method HTTP Code Description
answerSuccess($data) 200 Successful response with data
answerFail($data) 400 Client error with validation details
answerError($message) 500 Server error with message
answerNoContent() 200 Success with null data
answerInvalidUuid() 400 Invalid UUID format error
answerRecordNotFound() 404 Record not found error
answerEmptyPayload() 400 Empty request body error
answerRequired($field) 400 Required field missing error
answerColumnNotFound($column) 400 Database column not found error

Response Examples

answerInvalidUuid()

{
    "status": "fail",
    "data": [{
        "field": "id",
        "error": "invalidUuidFormat",
        "message": "The provided uuid format is invalid"
    }]
}

answerRecordNotFound()

{
    "status": "fail",
    "data": [{
        "field": "id",
        "error": "recordNotFound",
        "message": "The record was not found with the given id"
    }]
}

answerRequired('email')

{
    "status": "fail",
    "data": [{
        "field": "email",
        "error": "required",
        "message": "The \"email\" field is required"
    }]
}

Framework Integration

Slim Framework

<?php

use DevToolbelt\JsendPayload\AnswerTrait;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class CreateUserAction
{
    use AnswerTrait;

    public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $data = $request->getParsedBody();

        if (empty($data)) {
            return $this->answerEmptyPayload();
        }

        if (empty($data['email'])) {
            return $this->answerRequired('email');
        }

        $user = $this->userService->create($data);

        return $this->answerSuccess($user, HttpStatusCode::CREATED);
    }
}

Laravel

<?php

namespace App\Http\Controllers;

use DevToolbelt\JsendPayload\AnswerTrait;
use Illuminate\Http\Request;
use Psr\Http\Message\ResponseInterface;

class UserController extends Controller
{
    use AnswerTrait;

    public function store(Request $request): ResponseInterface
    {
        $validated = $request->validate([
            'name' => 'required|string',
            'email' => 'required|email|unique:users',
        ]);

        $user = User::create($validated);

        return $this->answerSuccess($user, HttpStatusCode::CREATED);
    }
}

Note: Laravel requires the nyholm/psr7 bridge or similar PSR-7 adapter for full compatibility.

Mezzio (formerly Zend Expressive)

<?php

namespace App\Handler;

use DevToolbelt\JsendPayload\AnswerTrait;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class UserHandler implements RequestHandlerInterface
{
    use AnswerTrait;

    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $id = $request->getAttribute('id');
        $user = $this->repository->find($id);

        if (!$user) {
            return $this->answerRecordNotFound();
        }

        return $this->answerSuccess($user->toArray());
    }
}

Symfony

<?php

namespace App\Controller;

use DevToolbelt\JsendPayload\AnswerTrait;
use DevToolbelt\Enums\Http\HttpStatusCode;
use Psr\Http\Message\ResponseInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class UserController extends AbstractController
{
    use AnswerTrait;

    #[Route('/api/users/{id}', name: 'api_user_show', methods: ['GET'])]
    public function show(string $id, UserRepository $repository): ResponseInterface
    {
        $user = $repository->find($id);

        if (!$user) {
            return $this->answerRecordNotFound();
        }

        return $this->answerSuccess([
            'id' => $user->getId(),
            'name' => $user->getName(),
            'email' => $user->getEmail(),
        ]);
    }

    #[Route('/api/users', name: 'api_user_create', methods: ['POST'])]
    public function create(Request $request, UserRepository $repository): ResponseInterface
    {
        $data = json_decode($request->getContent(), true);

        if (empty($data)) {
            return $this->answerEmptyPayload();
        }

        if (empty($data['email'])) {
            return $this->answerRequired('email');
        }

        $user = $repository->create($data);

        return $this->answerSuccess($user, HttpStatusCode::CREATED);
    }
}

Note: Symfony requires the PSR-7 Bridge (symfony/psr-http-message-bridge) for PSR-7 response compatibility.

Yii2

<?php

namespace app\controllers;

use DevToolbelt\JsendPayload\AnswerTrait;
use DevToolbelt\Enums\Http\HttpStatusCode;
use Psr\Http\Message\ResponseInterface;
use yii\web\Controller;

class UserController extends Controller
{
    use AnswerTrait;

    public function actionView(string $id): ResponseInterface
    {
        $user = User::findOne($id);

        if (!$user) {
            return $this->answerRecordNotFound();
        }

        return $this->answerSuccess($user->toArray());
    }

    public function actionCreate(): ResponseInterface
    {
        $data = \Yii::$app->request->getBodyParams();

        if (empty($data)) {
            return $this->answerEmptyPayload();
        }

        $user = new User();
        $user->load($data, '');

        if (!$user->validate()) {
            return $this->answerFail(
                array_map(fn($field, $errors) => [
                    'field' => $field,
                    'error' => 'validation',
                    'message' => implode(', ', $errors),
                ], array_keys($user->errors), $user->errors)
            );
        }

        $user->save();

        return $this->answerSuccess($user->toArray(), HttpStatusCode::CREATED);
    }
}

Note: For Yii2, you may need to configure your application to handle PSR-7 responses or convert them using yiisoft/yii2-psr7-bridge.

CakePHP 5

<?php

declare(strict_types=1);

namespace App\Controller\Api;

use App\Controller\AppController;
use DevToolbelt\JsendPayload\AnswerTrait;
use DevToolbelt\Enums\Http\HttpStatusCode;
use Psr\Http\Message\ResponseInterface;

class UsersController extends AppController
{
    use AnswerTrait;

    public function view(string $id): ResponseInterface
    {
        $user = $this->Users->find()
            ->where(['id' => $id])
            ->first();

        if (!$user) {
            return $this->answerRecordNotFound();
        }

        return $this->answerSuccess($user->toArray());
    }

    public function add(): ResponseInterface
    {
        $data = $this->request->getData();

        if (empty($data)) {
            return $this->answerEmptyPayload();
        }

        $user = $this->Users->newEntity($data);

        if ($user->hasErrors()) {
            $errors = [];
            foreach ($user->getErrors() as $field => $fieldErrors) {
                foreach ($fieldErrors as $error => $message) {
                    $errors[] = [
                        'field' => $field,
                        'error' => $error,
                        'message' => $message,
                    ];
                }
            }
            return $this->answerFail($errors);
        }

        $this->Users->save($user);

        return $this->answerSuccess($user->toArray(), HttpStatusCode::CREATED);
    }
}

Note: CakePHP 5 has native PSR-7 support. For CakePHP 4, the integration works similarly.

CodeIgniter 4

<?php

namespace App\Controllers\Api;

use CodeIgniter\RESTful\ResourceController;
use DevToolbelt\JsendPayload\AnswerTrait;
use DevToolbelt\Enums\Http\HttpStatusCode;
use Psr\Http\Message\ResponseInterface;

class UserController extends ResourceController
{
    use AnswerTrait;

    protected $modelName = 'App\Models\UserModel';

    public function show($id = null): ResponseInterface
    {
        $user = $this->model->find($id);

        if (!$user) {
            return $this->answerRecordNotFound();
        }

        return $this->answerSuccess($user);
    }

    public function create(): ResponseInterface
    {
        $data = $this->request->getJSON(true);

        if (empty($data)) {
            return $this->answerEmptyPayload();
        }

        $validation = \Config\Services::validation();

        if (!$validation->run($data, 'userRules')) {
            $errors = [];
            foreach ($validation->getErrors() as $field => $message) {
                $errors[] = [
                    'field' => $field,
                    'error' => 'validation',
                    'message' => $message,
                ];
            }
            return $this->answerFail($errors);
        }

        $userId = $this->model->insert($data);
        $user = $this->model->find($userId);

        return $this->answerSuccess($user, HttpStatusCode::CREATED);
    }

    public function update($id = null): ResponseInterface
    {
        $user = $this->model->find($id);

        if (!$user) {
            return $this->answerRecordNotFound();
        }

        $data = $this->request->getJSON(true);

        if (empty($data)) {
            return $this->answerEmptyPayload();
        }

        $this->model->update($id, $data);

        return $this->answerSuccess($this->model->find($id));
    }

    public function delete($id = null): ResponseInterface
    {
        $user = $this->model->find($id);

        if (!$user) {
            return $this->answerRecordNotFound();
        }

        $this->model->delete($id);

        return $this->answerNoContent();
    }
}

Note: CodeIgniter 4 supports PSR-7 through the codeigniter4/psr7bridge package for full compatibility.

Testing

# Run tests
composer test

# Run tests with coverage
composer test:coverage

# Static analysis
composer phpstan

# Code style check
composer phpcs

# Fix code style
composer phpcs:fix

Security

If you discover any security-related issues, please email dersonsena@gmail.com instead of using the issue tracker.

Code Quality Requirements

Check Tool Requirement
Tests PHPUnit All tests must pass
Coverage PCOV Minimum 85% coverage
Code Style PHP CodeSniffer PSR-12 compliant
Static Analysis PHPStan Level 6, no errors

Pull Request Guidelines

Before submitting a PR, ensure:

  1. All tests pass: composer test
  2. Coverage is at least 85%: composer test:coverage
  3. Code style is correct: composer phpcs
  4. No static analysis errors: composer phpstan

Important: Pull requests with coverage below 85% will be automatically blocked by CI.

Coverage Report

License

MIT License. See LICENSE for details.

dev-toolbelt/jsend-payload 适用场景与选型建议

dev-toolbelt/jsend-payload 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.61k 次下载、GitHub Stars 达 2, 最近一次更新时间为 2026 年 02 月 01 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「json」 「http」 「rest」 「api」 「response」 「jsend」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 dev-toolbelt/jsend-payload 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 dev-toolbelt/jsend-payload 我们能提供哪些服务?
定制开发 / 二次开发

基于 dev-toolbelt/jsend-payload 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-02-01