kelemen/api-nette

Nette 框架的 API

1.0.1 2017-10-26 06:31 UTC

This package is auto-updated.

Last update: 2024-09-23 23:32:40 UTC


README

高度可定制且易于设置的 Nette 框架 RESTful API 处理。

Scrutinizer Code Quality Code Coverage Build Status Packagist

SensioLabsInsight

安装

composer require kelemen/api-nette

准备使用

  1. 首先,您需要一个用于处理 API 请求的 API 展示器。您可以使用 Kelemen\ApiNette\Presenter\ApiPresenter 或自己编写。

  2. 在 config.neon 中注册新的映射

    application:
        mapping:
            Api: Kelemen\ApiNette\Presenter\*Presenter
  3. 将 API 路由添加到路由器中。我们使用关键字 api 来识别 API 请求。

    $router[] = new Route("api/<params .*>", [
        'presenter' => 'Api',
        'action' => 'default'   
    ]);
  4. 配置 API(示例来自 config.neon)

    services:
        - Kelemen\ApiNette\Logger\Storage\DummyLoggerStorage
        - Kelemen\ApiNette\Logger\Logger
        api:
            class: Kelemen\ApiNette\Api
            setup:
                - get('users', 'Custom\Users\ListHandler')
                - get('users/<id>', 'Custom\Users\DetailHandler')
                - put('users/<id>', 'Custom\Users\CrateHandler', [middleware: ['Custom\Auth\Bearer'])
                - post('users/<id>', 'Custom\Users\UpdateHandler', [middleware: ['Custom\Auth\Bearer']])

API 路由

将路由添加到 API

可以使用快捷函数(用于大多数使用的 HTTP 方法)定义 RESTful API 路由。

  • get
  • post
  • put
  • patch
  • delete
  • options

或者,您可以使用 add($method, $pattern, $handler, $params = []) 函数添加任何 HTTP 方法处理。

$api = new Api(...);
$api->add('purge', 'purge/urls', 'Handlers\PurgeHandler')

路由模式

在路由定义中,您可以使用正则表达式或定义在 <> 之间的参数。路由按添加的顺序评估。因此,首先定义特定路由。

$api = new Api(...);
$api->get('users', 'Handler');         // exact match for (with our route) /api/users
$api->get('users/<id>', 'Handler');    // parse parameter id from routes like /api/users/10, /api/users/sdk-2323 etc.
$api->get('users/<id>/message/<messageId>', 'Handler'); // parse parameters id and messageId from matched requests

// Optional parameters are not supported. If optional parameter is needed we have to define multiple routes.
$api->get('users/<id>/message', 'Handler');
$api->get('users/<id>/message/<messageId>', 'Handler');

// In route definition we can use any regular expression.
$api->options('.*', 'Handler');          // process OPTIONS call for any incoming URL

路由处理程序

路由定义使用 Nette DI 容器的 延迟加载。处理程序通过 类型 或通过在 config.neon 文件中注册的 名称 定义。对于名称定义,在服务名称前缀加上 #

$api = new Api(...);
$api->get('users', 'Full\Namespace\For\Handler');       // By type
$api->get('users/<id>', '#registeredHandlerName');      // By name

路由参数

现在仅接受 中间件 键作为参数。中间件定义使用与处理程序相同的 延迟加载 逻辑。

$api = new Api(...);
$api->get('users', 'Full\Namespace\For\Handler', ['middleware' => [
    'Middleware\Auth\Bearer',   // By type
    '#bearerAuthorization'      // By name
]]);

处理程序

处理程序提供已解析 API 路由的业务逻辑。

use Nette\Http\Request;
use Nette\Http\Response;
use Kelemen\ApiNette\Handler\BaseHandler;
use Kelemen\ApiNette\Response\JsonApiResponse;
use Kelemen\ApiNette\Validator\Validation;

class UserGetHandler extends BaseHandler
{
    // Here we can define validation rules for input parameters (see section Validations below).
    // This function is optional.
    public function validate()
    {
        return [
            new Validation('path', 'id', 'required|integer'),
            new Validation('get', 'page', 'integer:1..100')
        ];
    }

    // Main function. Process request and return ApiResponse.
    public function __invoke(Request $request, Response $response, callable $next)
    {
        // ... do some business logic as filtering, database requests etc.
        
        // All validated values are acessible via $this->values array
        $id = $this->values['id'];
        if ($id && isset($this->values['page'])) {
            ...
        }
        
        return new JsonApiResponse(200, ['data' => [
            'id' => 1,
            'name' => 'Samuel'
        ]]);
    }
}

验证

重要!每个参数都解析为字符串!因此,请使用 数字 验证规则而不是整数或浮点数。

主要验证由 Nette 验证器 处理。验证在处理程序的 validate() 函数中注册。所有已验证输入参数都可通过处理程序的 $this->values 数组访问。

如果任何验证失败,API 会自动发送带有 400 HTTP 代码的响应,并包含所有验证错误。

自定义验证规则

默认情况下,您不需要将新的 Validator 实例注册到 API。但如果您想注册新的验证或覆盖现有的验证,您需要创建并配置自己的 Validator 实例。

$validator = new Kelemen\ApiNette\Validator\Validator();
$validator->setValidator('enum', function ($value, $ruleParams = null) {
    // $value - contains parameter value
    // $ruleParams - contains string from parsed rule after ":"
    return in_array($value, explode(',', $ruleParams));
});

// Usage in validation funciton ...

public function validate()
{
    return new Validation('get', 'name', 'required|enum:Samuel,Peter')
}

输入

验证器定义了默认的输入集

如果您想添加特殊输入,您可以使用 setInput($name, InputInterface $input) 函数将此输入添加到验证器中。

中间件

可以通过中间件扩展 API 流程。中间件接口只有一个函数 __invoke(Request $request, Response $response, callable $next)。中间件是如何工作的

use Kelemen\ApiNette\Middleware\Middleware;
use Nette\Http\Request;
use Nette\Http\Response;

class CustomMiddleware implements Middleware
{
    public function __invoke(Request $request, Response $response, callable $next)
    {
        // This code is executed before handler (Optional)
        // Example: provide authentification here. If user is authenticated call $next() if no return new response
        if ($request->isSecured()) {
            // Do something ...
        }

        // Call next middleware or handler if last middleware (Optional)
        $resp = $next($request, $response);

        // This code is executed after handler (Optional)
        // Example: add CORS headers here
        $response->setHeader('custom header', 'header value');

        // Mandatory! Every middleware has to return response!
        return $resp;
    }

}

如果我们注册了 3 个中间件

['middleware1', 'middleware2', 'middleware3']

流程将如下所示

- middleware1
    - middleware2
        - middleware3
            - handler (return Nette\Application\IResponse)
        - middleware3
    - middleware2
- middleware1

流程和异常

库附带默认的 API 展示器 Kelemen\ApiNette\Presenter\ApiPresenter。此展示器运行 API 并处理所有异常(根据捕获的异常创建响应)。如果您想自定义错误响应,创建并注册自己的展示器。

API 抛出以下异常

基本实现

中间件

CORSMiddleware

设置 Access-Control-Allow-OriginAccess-Control-Allow-Credentials 标头。中间件有 3 种模式

  • all - 返回允许源为 "*"。凭据标头通过标准禁用。
  • 镜像 - 返回请求头 "Origin",允许源(allow-origin)和凭据(credentials)头可以手动配置。
  • 自定义 - 必须配置允许源(allow-origin)头,凭据(credentials)头可以手动配置。

处理程序

OptionsPreflightHandler

可配置的浏览器 CORS 预检请求处理器。可配置的响应头

  • Access-Control-Max-Age
  • Access-Control-Expose-Headers
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers