ccasanovas / cakeapigateway
CakePHP 的 ApiGatewaySDK 插件
1.0.5
2023-02-04 23:50 UTC
Requires
- cakephp/cakephp: 4.*
Requires (Dev)
- phpunit/phpunit: ^9.5
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 Headers(https://tools.ietf.org/html/rfc5988)
- 包含
FlattenedFieldsTrait
trait,用于 API 中使用的模型,以简化与 API 的兼容性方法和操作创建。- 此 Trait 简化了本地表与 API 定义之间的映射。
- 这允许完全分离 API 定义与表内部结构
- 它还负责格式化验证错误,以确保与 API 定义的格式相匹配。
- 包含
UnprocessableEntityException
异常,用于处理 API 收到的格式和验证错误的数据。 - 包含异常渲染器
ApiExceptionRenderer
,以便正确处理 API 触发的异常
安装
要使用 composer 获取插件,需要在 composer.json
中添加以下内容:
- 向
"require"
对象添加插件:"ccasanovas/cake-apigateway": "dev-master"
- 向
"repositories"
数组添加对象:{"type": "vcs", "url": "git@bitbucket.org:ccasanovas/cake-apigateway.git"}
- 运行
composer update
注意:确保在存储库中具有正确的访问/部署权限。
一旦在存储库中安装了插件,就可以:
- 将组件
$this->loadComponent('Ccasanovas/ApiGatewaySDK.ApiRequest');
添加到 API 控制器中 - 将 FlattenedFields trait 添加到需要它的表:
use Ccasanovas\ApiGatewaySDK\Traits\FlattenedFieldsTrait;
- 在
app.php
中配置应用程序以使用异常渲染器,设置Error.exceptionRenderer
为Ccasanovas\ApiGatewaySDK\Error\ApiExceptionRenderer
结构
Ccasanovas\ApiGatewaySDK\Controller\Component\ApiRequestComponent
- public $_apiRoute = null
- 用于生成 Link Headers 的内部变量。有关更多信息,请参阅
getLinkHeaders
- 用于生成 Link Headers 的内部变量。有关更多信息,请参阅
- public beforeFilter(Event $event)
- 在此回调中,组件负责:
- 检查是否存在并匹配配置的
X-Amzn-Apigateway-Api-Id
标头 - 确保
Content-Type
标头对于 PUT、POST 和 PATCH 类型的请求为application/json
- 确保
Accept
标头为application/json
- 检查是否存在并匹配配置的
- 在此回调中,组件负责:
- public beforeRender(Event $event)
- 在此回调中,组件负责:
- 配置响应,包含必要的 CORS 标头
- 设置分页器的变量,如果使用过,则在响应的
paging
数组中。 - 如果有,设置分页的
Link
头部。 - 确保所有视图变量都已序列化。
- 还负责在序列化响应之前清除视图变量
_apiRoute
。
- 在此回调中,组件负责:
Ccasanovas\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() ])
Ccasanovas\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格式,而不是像CakePHP那样的格式。
- 对于每个字段,都有一个包含错误的数组。每个错误都是一个包含其
code
和message
的数组。将CakePHP的验证错误转换为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' ], ] ]
Ccasanovas\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
方法的一个特性是它允许映射关联实体的字段,例如,此映射用于一个与BankAccounts
通过hasMany
关联的实体,并且想要通过别名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的内部事务中。
- 此方法在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, ]