seiger/sapi 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

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

seiger/sapi

Composer 安装命令:

composer require seiger/sapi

包简介

API tools package for Evolution CMS.

README 文档

README

sApi is a lightweight, framework-agnostic API core for Evolution CMS, designed to build modern, versioned JSON APIs with Laravel-style routing and JWT authentication.

The package provides only the essential infrastructure:

  • routing
  • middleware
  • authentication
  • extensibility for other packages

Business logic, CRUD scaffolding, GraphQL, and API documentation are intentionally out of scope of the core and should be implemented via separate modules.

Key Features

  • ✅ Single front controller (/api/index.php, /rest/index.php, etc.)
  • ✅ Laravel-style routing (based on illuminate/routing)
  • ✅ API versioning via URL (/v1/...)
  • ✅ JWT authentication (Bearer tokens)
  • ✅ Middleware with scope-based authorization
  • ✅ JSON-only responses (no XML, no GraphQL)
  • ✅ Automatic discovery of API routes from other packages
  • ✅ OpenAPI-friendly response conventions
  • ✅ Designed for Evolution CMS ecosystem

Requirements

  • PHP 8.4+
  • Evolution CMS 3.5+
  • Composer

Installation

composer require seiger/sapi

Environment Variables

Recommended location: core/custom/.env (EvolutionCMS loads it in core/bootstrap.php).

Variable Default Description
SAPI_BASE_PATH api Base prefix for all sApi routes (e.g. rest/rest/token).
SAPI_VERSION v1 Optional API version prefix (e.g. v1/api/v1/token). Leave empty to use unversioned routes.
SAPI_JWT_SECRET (empty) HS256 secret used to sign/verify JWTs. Required to issue tokens.
SAPI_JWT_TTL 3600 Token TTL in seconds.
SAPI_JWT_SCOPES * Default token scopes (comma-separated).
SAPI_JWT_ISS (empty) Optional iss claim.
SAPI_LOGGING_ENABLED 1 Enable/disable all sApi logging.
SAPI_LOG_ACCESS_ENABLED 1 Enable/disable access log entries.
SAPI_LOG_EXCLUDE_PATHS (empty) Comma-separated paths to skip from access logging (e.g. /rest/health).
SAPI_LOG_BODY_ON_ERROR 1 Log request body for 4xx/5xx.
SAPI_LOG_MAX_BODY_BYTES 4096 Max request body bytes to log.
SAPI_LOG_AUDIT_ENABLED 1 Enable/disable audit events logging.
SAPI_AUDIT_EXCLUDE_EVENTS (empty) Comma-separated event patterns to skip (supports * via fnmatch).
SAPI_AUDIT_MAX_CONTEXT_BYTES 8192 Max audit context size.
SAPI_REDACT_BODY_KEYS password,token,refresh_token,jwt,secret Keys to redact in logged bodies/contexts.
APP_NAME evo Used as Monolog channel name for the sapi logger.
LOG_LEVEL debug Log level for the sapi logger.
LOG_DAILY_DAYS 14 Retention days for daily logs.

Basic Concept

sApi acts as an API kernel, not a full framework.

You create a single front controller file (for example /api/index.php), bootstrap Evolution CMS, and let sApi handle:

  • routing
  • authentication
  • middleware execution
  • request dispatching

All API endpoints are defined via route providers.

Front Controller Example

<?php
declare(strict_types=1);

define('EVO_API_MODE', true);
define('IN_MANAGER_MODE', false);

require_once dirname(__DIR__) . '/index.php';

require_once EVO_BASE_PATH . 'vendor/autoload.php';

use Seiger\sApi\Kernel;

$kernel = new Kernel($modx);
$kernel->handle();

The base API path is configured via SAPI_BASE_PATH (e.g. api, rest).

Routing

sApi uses Laravel-style routing internally.

Example (core routes)

$router->group(['prefix' => 'v1'], function () use ($router) {
    $router->get('health', function () {
        return new JsonResponse(['ok' => true]);
    });
});

JWT Authentication

sApi supports Bearer JWT authentication.

Authorization: Bearer <jwt-token>

Issuing a Token

To get a JWT, call the built-in token endpoint:

  • POST /{SAPI_BASE_PATH}/{SAPI_VERSION}/token (if SAPI_VERSION is empty → /{SAPI_BASE_PATH}/token)
  • Body (JSON): { "username": "manager_user", "password": "..." }
  • Access is restricted by the sapi_access role permission. The package migration creates the ApiUser role and grants this permission to it by default.

Success response:

{
  "data": {
    "access_token": "....",
    "token_type": "Bearer",
    "expires_in": 3600
  }
}

Middleware

$router->group(['middleware' => ['jwt:orders:read']], function () use ($router) {
    $router->get('orders', OrdersController::class . '@index');
});

JWT payload example:

{
  "sub": 12,
  "scopes": ["orders:read", "orders:write"],
  "exp": 1710000000
}

Access Logging (JSON lines)

sApi writes access logs for every API request under SAPI_BASE_PATH (except exclude_paths) in JSON lines format using the standard Evolution/Laravel logger (Monolog daily).

  • Daily file: core/storage/logs/sapi-YYYY-MM-DD.log
  • Retention: LOG_DAILY_DAYS (default 14)

Configuration is via .env variables (see SAPI_LOG_* and SAPI_REDACT_BODY_KEYS above).

Notes:

  • Response always includes X-Request-Id.
  • Authorization / cookies are never written to access logs.
  • Request body is logged only for 4xx/5xx (with redaction + size limit).

Audit Logging (Business Events)

Audit logs are explicit business events (e.g. token.issued, orders.updated) written as JSON lines into the same daily sapi log channel (timeline-friendly).

  • Daily file: core/storage/logs/sapi-YYYY-MM-DD.log
  • Retention: LOG_DAILY_DAYS (default 14)

Example:

app(\Seiger\sApi\Logging\AuditLogger::class)->event('orders.updated', [
    'order_id' => 123,
    'status' => 'paid',
], 'notice');

Notes:

  • request_id, route, sub can be auto-filled from the current request context (when available).
  • Never log JWT tokens or secrets in audit context (redaction is applied by key name).

Route Providers (Extensibility)

Other packages (e.g. sCommerce, sSeo) can automatically register their API endpoints.

Interface

use Illuminate\Routing\Router;

interface RouteProviderInterface
{
    public function register(Router $router): void;
}

Example Provider (in another package)

final class OrdersRouteProvider implements RouteProviderInterface
{
    public function register(Router $router): void
    {
        $router->group(['prefix' => 'orders', 'middleware' => ['jwt:orders:read']], function () use ($router) {
            $router->get('', [OrdersController::class, 'index'])->name('index');
        });
    }
}

Composer Auto-Discovery

{
  "extra": {
    "sapi": {
      "route_providers": [
        { "class": "Seiger\\sCommerce\\Api\\Routes\\OrdersRouteProvider", "endpoint": "orders" },
        { "class": "Seiger\\sCommerce\\Api\\Routes\\LegacyOrdersRouteProvider", "endpoint": "orders", "version": "v0" }
      ]
    }
  }
}

Rules:

  • endpoint is required.
  • version is optional; if omitted, SAPI_VERSION is used (can be empty for unversioned routes).
  • Cache key is {version}/{endpoint} or {endpoint} when version is empty.
  • Priority: core/custom/composer.json overrides vendor entries.
  • Route name prefix: sApi.{endpoint}.{version}.… (version is omitted when empty).
  • Providers must register routes without SAPI_BASE_PATH and without version in the URI (sApi applies them).

Cache

Discovery is cached in core/storage/cache/sapi_routes_map.php and is rebuilt only when:

  • core/composer.lock changes (mtime/size)
  • core/custom/composer.json changes (mtime/size), if the file exists
  • SAPI_VERSION changes
  • SAPI_BASE_PATH changes

Response Conventions

sApi keeps responses intentionally simple and OpenAPI-friendly.

Success responses

Successful responses use a top-level data member.

{
  "data": {}
}

For named collections:

{
  "data": {
    "categories": [
      {
        "id": 1,
        "title": "News",
        "alias": "news"
      }
    ]
  }
}

An optional message field may be included when it adds useful human context.

Error responses

Error responses use application/problem+json and follow RFC 9457:

{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid token."
}

Validation-style extensions may be added as extra members, for example errors.

Design rules

  • use snake_case JSON keys
  • prefer data over generic wrappers such as object
  • do not duplicate the HTTP status code in the body by default
  • prefer standard fields like access_token, token_type, expires_in
  • keep business payloads inside data

See also: docs/response-conventions.md

OpenAPI / Swagger

sApi is designed to be compatible with OpenAPI 3.1.

Recommended standards around the core:

  • OpenAPI 3.1 for contract description
  • RFC 9457 for error responses (application/problem+json)
  • familiar OAuth 2 token response fields for access tokens

Documentation generation and Swagger UI are not included in the core
and will be provided via a separate module.

License

This package is licensed under the GNU General Public License v3.0.

You are free to use it in commercial and non-commercial projects.
If you distribute modified versions or derivative works, they must also be licensed under GPLv3.

See the LICENSE file for details.

Roadmap (High-Level)

  • JWT refresh tokens
  • Rate limiting middleware
  • OpenAPI documentation module
  • CLI helpers for API debugging
  • Request validation helpers

Philosophy

Explicit over magic.
Infrastructure, not business logic.
Composable, not monolithic.

sApi is intentionally minimal.
If you need full-stack API automation, use a framework.
If you need a solid API core for Evolution CMS — this is it.

seiger/sapi 适用场景与选型建议

seiger/sapi 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 85 次下载、GitHub Stars 达 1, 最近一次更新时间为 2026 年 01 月 05 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

围绕 seiger/sapi 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: GPL-3.0
  • 更新时间: 2026-01-05