evil-corp / cakephp-awsapigateway
CakePHP 的 AwsApiGateway 插件
v2.3.3
2020-08-31 19:36 UTC
Requires
- cakephp/cakephp: ^3.4
Requires (Dev)
- phpunit/phpunit: ^5.7|^6.0
README
此插件包含用于创建和部署 AWS ApiGateway 应用程序的实用工具。
变更日志
日期:2020-08-31
- 为 CakePHP 3.8.* 代码弃用更改
日期: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)
- 包括用于 API 中使用的模型的
FlattenedFieldsTrait
,这简化了本地表与 API 定义之间的映射。- 此 trait 简化了本地表与 API 定义之间的映射。
- 这允许完全分离 API 的定义与表的内结构
- 还负责将验证错误格式化为与 API 定义的格式一致
- 包括
UnprocessableEntityException
异常,用于处理 API 接收到的格式和验证错误的数据。 - 包括异常渲染器
ApiExceptionRenderer
,以便正确处理 API 抛出的异常
安装
要使用 composer 获取插件,需要在 composer.json
中添加以下内容:
- 向
"require"
对象添加插件:"evil-corp/cakephp-awsapigateway": "dev-master"
- 向
"repositories"
数组添加对象:{
"type": "vcs", "url": "git@bitbucket.org:evil-corp/cakephp-awsapigateway.git"}
- 运行
composer update
注意:请确保您有对存储库的访问/部署的正确权限。
一旦在存储库中安装了插件,就可以:
- 向 API 控制器添加组件:
$this->loadComponent('EvilCorp/AwsApiGateway.ApiRequest');
- 向需要它们的表添加 FlattenedFields trait:
use EvilCorp\AwsApiGateway\Traits\FlattenedFieldsTrait;
- 在
app.php
中设置以使用异常渲染器,将Error.exceptionRenderer
设置为EvilCorp\AwsApiGateway\Error\ApiExceptionRenderer
结构
EvilCorp\AwsApiGateway\Controller\Component\ApiRequestComponent
- public $_apiRoute = null
- 内部变量,用于生成 Link 头。有关更多信息,请参阅
getLinkHeaders
- 内部变量,用于生成 Link 头。有关更多信息,请参阅
- public beforeFilter(Event $event)
- 在此回调中,该组件负责:
- 检查
X-Amzn-Apigateway-Api-Id
标头是否存在且与配置匹配 - 确保
Content-Type
标头对于 PUT、POST 和 PATCH 类型的请求是application/json
- 确保头部
Accept
为application/json
- 检查
- 在此回调中,该组件负责:
- public beforeRender(Event $event)
- 在此回调中,该组件负责:
- 配置Response以包含必要的CORS头部
- 如果使用过,在Response的
paging
数组中设置Paginator变量。 - 如果存在,设置用于分页的
Link
头部。 - 确保所有viewVars都已序列化。
- 在序列化响应之前,也负责清理viewVar
_apiRoute
。
- 在此回调中,该组件负责:
- protected getLinkHeaders($paging, $controller)
- 用于生成Link头部。
- 如果需要,可以从Controller中设置变量
_apiRoute
以覆盖自动生成URL。当生成的Link头部与期望的路径不一致时使用。例如$this->set('_apiRoute', [ 'prefix' => 'Api/v1', 'controller' => 'News', 'action' => 'index', '_method' => 'GET', 'plugin' => false, 'owners_association_id' => $this->request->getParam('owners_association_id'), '?' => $this->request->getQueryParams(), ]);
EvilCorp\AwsApiGateway\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() ])
EvilCorp\AwsApiGateway\Error\ApiExceptionRenderer
- public UnprocessableEntity($exception)
- 此异常渲染器为
UnprocessableEntityException
类型的异常添加了支持。 - 负责在Response中设置相应的变量。
- 如果有验证错误,则将其设置在响应对象的'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' ], ] ]
EvilCorp\AwsApiGateway\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
,将每个条目单独传递到$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 中将所有操作封装在一个事务中。
- 此方法在 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
)中保存的其余配置相同。
可用的配置:
'AwsApiGateway' => [
/*
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,
]
测试
//TODO