firehed / api
一个API框架
Requires
- php: ^7.0
- firehed/common: ^1.0
- firehed/input: ^2.0
- psr/container: ^1.0
- psr/http-message: ^1.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- psr/log: ^1.0
- zendframework/zend-diactoros: ^1.3 || ^2.0
Requires (Dev)
- firehed/arctools: ^1.0
- phpstan/phpstan: ^0.9.2
- phpstan/phpstan-phpunit: ^0.9.4
- phpunit/phpunit: ^6.0 | ^7.0
- squizlabs/php_codesniffer: ^3.1
Suggests
- firehed/inputobjects: Pre-made Input components for validation
- 8.1.x-dev
- dev-master / 4.0.x-dev
- 3.2.2
- 3.2.1
- 3.2.0
- 3.1.0
- 3.0.6
- 3.0.5
- 3.0.4
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 2.3.1
- 2.3.0
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.0
- 2.0.0
- 1.0.0
- 0.2.0
- 0.1.1
- 0.1.0
- 0.0.6
- 0.0.5
- 0.0.4
- 0.0.3
- 0.0.2
- 0.0.1
- dev-dependabot/composer/psr/http-message-tw-2.0
- dev-3_2_0
- dev-newer-php-fixes
- dev-real-enum
- dev-8.1-enums
- dev-upgrade-guide
- dev-inline_search
- dev-phpunit8
- dev-fastroute
This package is auto-updated.
Last update: 2024-09-20 17:10:31 UTC
README
安装
API通过composer提供
composer require firehed/api
使用
设置一个.apiconfig
文件,它包含框架的JSON格式设置。您可以通过运行vendor/bin/api generate:config
来执行此操作。有关更多信息,请参阅下面的配置。
生成默认的前端控制器
vendor/bin/api generate:frontController
在创建、修改或删除端点后,运行编译器
vendor/bin/api compile:all
这一步是必需的:框架依赖于生成的文件,而不是在运行时尝试执行相同的步骤。预计您将在每次构建/部署时使用上述命令重建文件。请参阅以下最佳实践部分。
测试
为了方便起见,包含了一个特性,其中包含对端点描述方法的测试。在您的测试用例类中(通常扩展PHPUnit\Framework\TestCase
),使用特性
\Firehed\API\Traits\EndpointTestCases
并添加一个返回待测端点实例的getEndpoint
方法。
示例
<?php namespace MyApp\API\Endpoints\User; use Firehed\API\Traits\EndpointTestCases; /** * @covers MyApp\API\Endpoints\User\Create */ class CreateTest extends \PHPUnit\Framework\TestCase { use EndpointTestCases; protected function getEndpoint() { return new Create(); } }
配置
在项目根目录中放置一个名为.apiconfig
的文件。它使用JSON格式。包含了一个控制台命令,可以引导您进行配置,可以通过运行vendor/bin/api generate:config
来调用。
选项
source
: 必需 字符串
扫描API端点的源代码目录。通常是src
。
namespace
: 必需 字符串
在搜索端点时过滤的命名空间。
webroot
: 必需 字符串
放置生成的前端控制器的目录。该值应为项目根目录的相对路径。
container
: 可选 字符串
返回PSR-11兼容容器以配置值的文件路径。
容器
如果在.apiconfig
中设置了container
值,API将了解容器(如果您不使用生成的前端控制器,也可以手动执行)。这是在运行时配置API端点的方式。按照惯例,如果容器has()
端点的完全限定类名,则分发器将get()
并使用该值在路由分发时使用。如果没有配置容器,或者容器没有路由端点的配置,则路由端点将通过new $routedEndpointClassName
简单地实例化。
其他自动检测的容器条目
示例
.apiconfig
:
{ "webroot": "public", "namespace": "Your\\Application", "source": "src", "container": "config.php" }
config.php
:
<?php use Firehed\API; use Psr\Log\LoggerInterface; use Your\Application\Endpoints; $container = new Pimple\Container(); // Endpoint config $container[Endpoints\UserPost::class] = function ($c) { return new Endpoints\UserPost($c['some-dependency']); }; // Other services $container[API\Authentication\ProviderInterface::class] = function ($c) { // return your provider }; $container[API\Authorization\ProviderInterface::class] = function ($c) { // return your provider }; $container[LoggerInterface::class] = function ($c) { return new Monolog\Logger('your-application'); }; // ... return new Pimple\Psr11\Container($container);
在此示例中,当您的UserPost
端点被路由时,它将使用容器中定义的端点 - 这允许端点具有必需的构造函数参数或其他配置。
如果您有一个UserGet
端点,它不在容器中,分发器将自动尝试用new
实例化它。如果该端点没有构造函数参数,这将很好。但是,这意味着如果它没有,您的应用程序将在运行时崩溃 - 因此,具有必需构造函数的任何端点必须在容器中配置。
身份验证和授权
为身份验证(谁在执行请求)和授权(是否允许执行请求)的过程分别定义了两个接口,分别命名为 Authentication\ProviderInterface
和 Authorization\ProviderInterface
。这两个接口将在容器中自动检测,并且必须提供。如果这两个接口都没有提供,则使用应用范围的处理程序将永远不会执行任何身份验证或授权。
任何实现 Interfaces\AuthenticatedEndpointInterface
的端点在执行之前将执行这些过程,并由身份验证提供者返回的容器提供。如果一个端点没有实现 Interfaces\AuthenticatedEndpointInterface
(即它只实现了 Interfaces\EndpointInterface
),则 将跳过应用范围内的身份验证。端点当然可以在其 execute()
方法中实现自己的身份验证协议,但除了登录页面之外(见下文),这被不推荐。
一般来说,上述接口的实现应该查找(几乎)每个请求中存在的身份验证数据:cookies、OAuth Bearer 令牌、HTTP 基本认证等,并验证其真实性。通常用于获取身份验证数据(例如 OAuth 授权)的端点通常不会进行身份验证,但会设置或返回用于对其他请求进行身份验证的数据。
示例提供者,实现了上述两个接口
<?php declare(strict_types=1); namespace Your\Project; use Firehed\API\Authentication\ProviderInterface as AuthnProvider; use Firehed\API\Authorization\Exception as AuthException; use Firehed\API\Authorization\ProviderInterface as AuthzProvider; use Firehed\API\Authorization\Ok; use Firehed\API\Container; use Firehed\API\Interfaces\AuthenticatedEndpointInterface; use Psr\Container\ContainerInterface; use Psr\Http\Message\ServerRequestInterface; // This elides a lot of details and error handling for simplicity class AuthProvider implements AuthnProvider, AuthzProvider { public function authenticate(ServerRequestInterface $request): ContainerInterface { list($_, $token) = explode(' ', $request->getHeaderLine('Authorization'), 2); // Find a user, app, etc. from the token string return new Container([ App::class => $app, User::class => $user, // ... 'oauth_scopes' => $scopes, ]); } public function authorize(AuthenticatedEndpointInterface $endpoint, ContainerInterface $container): Ok { $scopes = $container->get('oauth_scopes'); if (!$endpoint instanceof YourInternalScopeInterface) { throw new \LogicException('Endpoint is invalid'); } // This is a method in YourInternalScopeInterface $neededScopes = $endpoint->getRequiredScopes(); foreach ($neededScopes as $scope) { if (!in_array($scope, $scopes)) { throw new AuthException(sprintf('Missing scope %s', $scope)); } } return new Ok(); } }
错误处理
强烈建议不要处理在端点的 execute()
方法中抛出的大多数异常。相反,更愿意编写通过抛出异常而失败声明的服务,以及期望成功情况的端点。这不是一个绝对规则,但有助于避免深层嵌套的 try
/catch
块和其他错误处理复杂性。
API 框架负责捕获在端点的 execute()
方法期间抛出的所有异常,并将它们提供给专门的异常处理器。
强烈建议通过容器创建并提供默认错误处理器 Firehed\API\Errors\HandlerInterface
(见上表)。所有未处理的异常都将发送到该处理器,包括请求(以便根据 Accept
头等格式化响应)。
所有实现 Firehed\API\Interfaces\HandlesOwnErrorsInterface
(在 v4.0.0 之前的 EndpointInterface
的一部分)的端点都将使用抛出的异常调用其 handleException()
方法。此处理器将在默认错误处理器之前被调用。此方法 可以 选择忽略某些异常类(通过重新抛出它们),但必须在选择处理异常时返回一个 PSR ResponseInterface
。
最后,默认配置了一个全局回退处理器,该处理器将记录异常并返回一个通用的 500 错误。
最佳实践
源代码控制
当然要使用源代码控制。
以下模式应添加到源代码控制的忽略文件中,以排除生成的文件
__*__.*
构建自动化
强烈推荐(对于任何现代 PHP 应用程序)使用自动化构建。
此框架依赖于编译来提高性能。在部署之前必须运行编译过程,并在自动化构建期间运行。
vendor/bin/api compile:all
.
Docker
在 Docker 中运行没有特殊要求,除了在上述构建自动化部分中提到的。
这意味着您应该在安装 Composer 依赖项之后的 Dockerfile 中的任何位置都包含以下行
RUN vendor/bin/api compile:all
您 应该 还将所有源代码控制忽略文件添加到 .dockerignore
中。
兼容性
此框架试图严格遵守语义版本规则的规则。总之,这意味着给定一个名为 X.Y.Z
的版本
- 只有当
X
增加时,才会引入破坏性更改 - 新功能将在以下任一情况下引入:当
Y
增加时,或者当X
增加且Y
重置为0
- 错误修复可能在任何版本增量中引入
术语“破坏性变更”应理解为
- 向方法添加额外的必需参数
- 向接口添加额外的方法定义
- 紧化方法或函数参数的类型提示
- 放宽方法或函数的返回类型
- 删除任何公共方法(除非在标记为内部使用的类上)
- 额外的系统要求(PHP版本、扩展等)
- 重大的、非可选的行为变更
- 对文档化构建步骤的必需修改(例如
vendor/bin/api compile:all
)
破坏性变更不包括
- 删除依赖项(如果您隐式依赖于该框架的依赖项,您应显式将其添加到自己的
composer.json
) - 删除明确标记为内部使用的类或方法
- 在编译过程中生成的任何文件的格式或内容变更,包括完全添加或删除文件
尽可能,过时功能将通过 trigger_error(string, E_USER_DEPRECATED)
标记为过时(除发布说明之外)。请注意,根据您的PHP设置,这可能会导致抛出 ErrorException
。由于这是一个可配置的行为,它不被视为BC破坏。
此外,整个 Firehed\API
命名空间应被视为保留用于PSR-11容器自动检测的目的。也就是说,如果您在容器中使用以 Firehed\API
开头的键,您应该预期该键可能会被检索并使用,而无需明确选择该行为。