powersystem / cakeapigateway
CakePHP 的 ApiGatewaySDK 插件
1.0.05
2023-02-08 18:38 UTC
Requires
- cakephp/cakephp: 4.*
Requires (Dev)
- phpunit/phpunit: ^9.5
This package is not auto-updated.
Last update: 2024-10-03 02:18:21 UTC
README
此插件包含用于创建和部署 AWS ApiGateway 应用程序的实用工具。
变更日志
日期:2022-08-31
- 将 CakePHP 3.8.* 的过时代码更新到 4.3.*
日期:2019-04-15
- 为 ApiRequestComponent 添加了新选项,以启用允许的 Content-Types 的自定义
日期:2018-10-10
- 重写了整个 README,以指明最新的更改
- 此插件不再与旧版本兼容(旧于 v0.1.0 标签)
文档
功能
- 包括用于 API 控制器的
ApiRequestComponent
组件,具有以下功能:- 确保请求以 JSON 格式正确格式化
- 验证请求是否来自配置的 ApiGateway
- 为 APIGateway 启用 CORS
- 如果使用 PagintorComponent 在控制器中处理数据,则正确格式化分页变量
- 如果响应包含分页,则添加 Link 头(https://tools.ietf.org/html/rfc5988)
- 包括用于 API 中使用的模型的
FlattenedFieldsTrait
特性,这有助于创建与 API 兼容的方法和操作。- 此特性简化了本地表和 API 定义之间的映射。
- 这允许完全分离 API 定义和表的内部结构。
- 它还负责格式化验证错误,以与 API 定义的格式相匹配。
- 包括
UnprocessableEntityException
异常,用于处理 API 接收到的格式和验证错误。 - 包括异常渲染器
ApiExceptionRenderer
,以正确处理 API 触发的异常
安装
要使用 composer 获取此插件,需要在 composer.json
中添加以下内容:
- 向
"require"
对象添加插件:"PowerSystem/cake-apigateway": "dev-master"
- 向
"repositories"
数组添加对象:{"type": "vcs", "url": "git@bitbucket.org:PowerSystem/cake-apigateway.git"}
- 运行
composer update
注意:确保在存储库中具有正确的访问/部署权限。
一旦在存储库中安装了插件,就可以
- 将其添加到 API 控制器的组件中:
$this->loadComponent('PowerSystem/ApiGatewaySDK.ApiRequest');
- 将 FlattenedFields 特性添加到需要它的表:
use PowerSystem\ApiGatewaySDK\Traits\FlattenedFieldsTrait;
- 在
app.php
中配置应用程序以使用异常渲染器,将Error.exceptionRenderer
设置为PowerSystem\ApiGatewaySDK\Error\ApiExceptionRenderer
结构
PowerSystem\ApiGatewaySDK\Controller\Component\ApiRequestComponent
- public $_apiRoute = null
- 用于生成 Link 标头的内部变量。有关更多信息,请参阅
getLinkHeaders
- 用于生成 Link 标头的内部变量。有关更多信息,请参阅
- public beforeFilter(Event $event)
- 在此回调中,该组件负责
- 检查是否存在且与配置匹配的
X-Amzn-Apigateway-Api-Id
标头 - 确保对于 PUT、POST 和 PATCH 类型的请求,标头
Content-Type
为application/json
- 确保标头
Accept
为application/json
- 检查是否存在且与配置匹配的
- 在此回调中,该组件负责
- public beforeRender(Event $event)
- 在此回调中,该组件负责
- 配置响应以包含必要的 CORS 标头
- 如果使用了分页器,则在响应的
paging
数组中设置分页变量。 - 如果存在,设置分页的
Link
头部。 - 确保所有 viewVars 都已序列化。
- 在序列化响应之前,还需要清理 viewVar
_apiRoute
。
- 在此回调中,该组件负责
PowerSystem\ApiGatewaySDK\Error\UnprocessableEntityException
- public __construct($message = null, $code = 422)
- 此异常用于显示 API 请求中的验证错误。
- 使用错误代码 422,等同于 HTTP 异常
422 Unprocessable Entity
- 允许通过传入数组的方式在 $message 中设置验证错误。
throw new UnprocessableEntityException([ 'message' => 'Error de validación!', 'errors' => $entity->getErrors() ])
PowerSystem\ApiGatewaySDK\Error\ApiExceptionRenderer
- public UnprocessableEntity($exception)
- 此异常渲染器增加了对
UnprocessableEntityException
类型异常的支持。 - 负责设置响应中相应的变量。
- 如果有验证错误,则将其设置在响应对象的 'errors' 变量中。
throw new UnprocessableEntityException([ 'message' => __('Data Validation Failed'), 'errors' => $entity->getErrors() ]);
{ "message": "Data Validation Failed", "errors": { "email": [{ "code": "Empty", "message": "This field cannot be left empty" }] }, "url": "\/api\/v1\/me\/email", "code": 422 }
- 此异常渲染器增加了对
- protected formatErrors($entity_errors)
- 此方法用于将验证错误格式化为更通用的 API 格式,而不是 Cake-like 格式。
- 对于每个字段,都有一个包含错误的数组。每个错误都是一个包含其
code
和message
的数组。将 Cake 的验证错误转换为 API 标准。$errors = [ 'email' => [ '_empty' => 'This field cannot be left empty', 'email' => 'This field must be a valid email address' ] ]; pr($this->formatErrors($errors));
//resultado: [ 'email' => [ [ 'code' => 'Empty', 'message' => 'This field cannot be left empty' ], [ 'code' => 'Email', 'message' => 'This field must be a valid email address' ], ] ]
PowerSystem\ApiGatewaySDK\Traits\FlattenedFieldsTrait
- public flattenedFieldsMaps()
- 返回一个包含用于使用此 Trait 的方法的字段映射的数组。**重要的是在表中重写此方法,以便返回满足 API 结构所需的必要映射**。
- 为了能够使用
getFlattenedEntity
和setFlattenedEntity
,数组必须定义 'get' 和 'set' 映射。 - 映射定义为关联数组(
clave => valor
),其中 clave 对应于结果的字段名,而 valor 对应于输入数据中的字段名。例如[ 'get' => [ 'identificador' => 'id', 'nombre' => 'name' ], 'set' => [ 'id' => 'identificador', 'name' => 'nombre' ] ]
- 查看
mapFlattenedFields
以获取更多信息。
- protected getFlattenedFieldsMap($map_name, $flip = false)
- 此方法用于从
flattenedFieldsMaps
内部获取映射。 - 它还允许在需要时反转映射。
- 此方法用于从
- protected mapFlattenedFields($entity, $map, $callback)
- 此方法处理一个实体或数组
$entity
,使用 $map,将每个条目单独传递给 $callback 进行处理。 - 最常见的使用方法是结合
Hash::get
,例如//dentro de la Table $entity = $this->get($id); $map = $this->getFlattenedFieldsMap('get'); $result = $this->mapFlattenedFields($entity, $map, function($field, $entity){ return Hash::get($entity, $field); });
- 使用
Hash::get
允许我们以点表示法在映射中定义字段,例如[ 'index' => [ 'id' => 'id', 'title' => 'title', 'category' => 'news_category.name', 'thumbnail' => 'news_images.0.thumbnail', 'created_at' => 'created_at', 'created_by' => 'creator.full_name', 'modified_at' => 'modified_at', 'modified_by' => 'modifier.full_name', ] ]
mapFlattenedFields
方法的一个特性是它允许映射关联实体的字段,例如,此映射用于一个通过hasMany
与BankAccounts
关联的实体,并希望在别名cuentas
中公开它们。[ 'get' => [ 'id' => 'id', 'titulo' => 'title', 'cuentas' => [ 'entities' => 'bank_accounts', 'map' => [ 'banco' => 'bank.name', 'tipo' => 'bank_account_type.title', 'numero' => 'account_number', 'cbu' => 'account_cbu', ] ] ] ]
- 此方法处理一个实体或数组
- protected getFlattenedEntity($where = [], $contain = [])
- 此方法是一个基本包装器,用于演示如何使用映射来处理单个实体。
- 对于简单情况或作为创建自己的复杂方法的指南,请使用它。
- 该方法使用在
flattenedFieldsMaps
中定义的get
映射。 - 该方法被定义为受保护的,因为预期您将在自己的方法中使用它,而不是直接从控制器中调用它。
- 参数是透明的,与 CakePHP 3 中创建查询使用的参数等效。
- 参数
$where
定义查询的条件,将直接传递给 find 而不进行修改。 - 参数
$contain
定义查询的关联。 - 基本用法示例:
//dentro de la Table $entity = $this->get($id); $mapped_entity = $this->getFlattenedEntity(['id' => $id]);
- protected setFlattenedEntity(Callable $method, $error_map = null)
- 与
getFlattenedEntity
不同,此方法不是一个基本的保存包装器,而是用于与您自己的保存方法结合使用。 - 这通常是由于在API定义中对数据进行简化会导致保存过程更加复杂,且变化多端,难以轻易封装到本插件中。
- 这种灵活性允许例如,通过单个API端点同时保存到多个表格,所有操作都在setFlattenedEntity内部的transaction中完成。
- 此方法在try/catch中执行 Callable $method 提供的方法,确保验证或保存过程中的错误保持相同的映射格式。
- 重要的是Callable使用
saveOrFail
而不是save
,因为catch基于由saveOrFail发出的保存异常来正确格式化验证错误。 - 在映射验证错误时,方法将使用提供的 $error_map 中的映射,否则将回退到 'set' 映射。
- 一个典型的实现示例是
public function setPaymentNotification($flattened_data, $api_user_id) { //obtiene un error map custom1 $error_map = $this->getFlattenedFieldsMap('errors'); //llama al método setFlattenedEntity return $this->setFlattenedEntity(function() use ($flattened_data, $api_user_id){ /* encierra el proceso en una transacción para poder guardar en varias tablas y si alguna falla, revertir todos los cambios. */ return $this->getConnection()->transactional( function ($connection) use ($flattened_data, $api_user_id){ //mapeamos con set $fields_map = $this->getFlattenedFieldsMap('set'); $data = $this->mapFlattenedFields($flattened_data, $fields_map, function($field, $payment_notification){ return Hash::get($payment_notification, $field); }); //creamos entidad $payment_notification = $this->newEntity($data, [ 'associated' => ['FunctionalUnits'] ]); /* acá también se podrían guardar datos en otras tablas, por ejemplo tablas asociadas a esta entidad. */ //setteamos algunos campos manualmente $payment_notification->api_user_id = $api_user_id; /* finalmente usamos saveOrFail en todas nuestras operaciones para que el catch ataje las excepciones si el guardado falla. */ return $this->saveOrFail($payment_notification, [ 'associated' => ['FunctionalUnits'] ]); }); }, $error_map); }
- 与
配置变量
配置变量与其它配置一样保存在应用配置数组中(默认为 config/app.php
)。
可用的配置有
'ApiGatewaySDK' => [ /* Esto es para que las peticiones requieren el api_id que agrega APIGateway a las requests. Al setearlo como requerido, las peticiones que no vengan a través de APIGateway no serán aceptadas. */ 'api_id' => 'rlrr9c1dk8', 'require_api_id_header' => true, ]