Amazon API Gateway
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 Amazon AWS 入门

在 API Gateway 中设置方法请求

设置方法请求涉及在创建 RestApi 资源之后执行以下任务:

  1. 创建新的 API 或选择现有的 API 资源实体。

  2. 创建特定于新创建或选定的 API Resource 上的 HTTP 动词的 API 方法资源。此任务可进一步分为以下子任务:

    • 为方法请求添加 HTTP 方法

    • 配置请求参数

    • 定义请求正文的模型

    • 制定授权方案

    • 启用请求验证

您可以使用以下方法执行这些任务:

有关使用这些工具的示例,请参阅 初始化 API Gateway 中的 API 设置

设置 API 资源

在 API Gateway API 中,您通过 API 资源实体树公开可寻址的资源,树的根资源 (/) 位于层次结构顶部。根资源相对于 API 的基本 URL,其中包含 API 终端节点和阶段名称。在 API Gateway 控制台中,该基本 URI 称为 Invoke URI,会在 API 部署后在 API 的阶段编辑器中显示。

API 终端节点可以是默认主机名或自定义域名。默认主机名采用以下格式:

{api-id}.execute-api.{region}.amazonaws.com

在此格式中,{api-id} 表示 API Gateway 生成的 API 标识符。{region} 变量表示您在创建 API 时选择的 AWS 区域 (例如 us-east-1)。自定义域名是有效 Internet 域的便于用户识别的任何名称。例如,如果您已经注册 Internet 域 example.com,任何 *.example.com 都是有效的自定义域名。有关更多信息,请参阅创建自定义域名

对于 PetStore 示例 API,根资源 (/) 用于公开 Pet Store。/pets 资源表示 Pet Store 中提供的宠物集合。/pets/{petId} 公开指定标识符 (petId) 的单个宠物。{petId} 的路径参数是请求参数的一部分。

要设置 API 资源,您可以选择现有资源作为父资源,然后在此父资源下创建子资源。您开始时将根资源作为父资源,向此父资源添加资源,向这个子资源添加另一个资源作为新的父资源,依此类推,直到添加到其父标识符。然后将命名的资源添加到父资源。

借助 AWS CLI,您可以调用 get-resources 命令,以查找可供使用的 API 资源:

aws apigateway get-resources --rest-api-id <apiId> \ --region <region>

结果是当前可用的 API 资源的列表。对于我们的 PetStore 示例 API,此列表类似于以下内容:

{ "items": [ { "path": "/pets", "resourceMethods": { "GET": {} }, "id": "6sxz2j", "pathPart": "pets", "parentId": "svzr2028x8" }, { "path": "/pets/{petId}", "resourceMethods": { "GET": {} }, "id": "rjkmth", "pathPart": "{petId}", "parentId": "6sxz2j" }, { "path": "/", "id": "svzr2028x8" } ] }

每个项目都列出了资源 (id) (根资源除外) 的标识符、其直接父级 (parentId) 以及资源名称 (pathPart)。根资源的特殊之处在于不具有任何父级。选择某个资源作为父资源之后,调用以下命令添加子资源。

aws apigateway create-resource --rest-api-id <apiId> \ --region <region> \ --parent-id <parentId> \ --path-part <resourceName>

例如,要在 PetStore 网站上添加要销售的宠物食品,通过将 path-part 设置为 food 并将 parent-id 设置为 svzr2028x8 来将 food 资源添加到根 (/)。结果类似于以下内容:

{ "path": "/food", "pathPart": "food", "id": "xdsvhp", "parentId": "svzr2028x8" }

使用代理资源来简化 API 设置

随着业务的增长,PetStore 所有者可能决定添加食物、玩具及其他宠物相关的商品进行销售。为此,您可在根资源下添加 /food/toys 和其他资源。在每个销售类别下,您可能还需要添加更多资源,例如 /food/{type}/{item}/toys/{type}/{item} 等。这很麻烦。如果您决定在资源路径中添加一个中间层 {subtype} 以将路径层次结构更改为 /food/{type]/{subtype}/{item}/toys/{type}/{subtype}/{item} 等,这些更改将会中断现有的 API 设置。为了避免这种情况,您可以使用 API Gateway 代理资源一次性公开一组 API 资源。

API Gateway 将代理资源定义为要在提交请求时指定的资源的占位符。代理资源用 {proxy+} 的特殊路径参数表示,该路径通常被称为“贪婪”路径参数。+ 号表示其附加了哪些子资源。/parent/{proxy+} 占位符表示与 /parent/* 路径模式匹配的任何资源。“贪婪”路径参数名称 proxy 可以按照与处理常规路径参数名称相同的方法用其他字符串替换。

使用 AWS CLI,您可以调用以下命令来设置根 (/{proxy+}) 下的代理资源:

aws apigateway create-resource --rest-api-id <apiId> \ --region <region> \ --parent-id <rootResourceId> \ --path-part {proxy+}

结果类似于以下内容:

{ "path": "/{proxy+}", "pathPart": "{proxy+}", "id": "234jdr", "parentId": "svzr2028x8" }

对于 PetStore API 示例,您可以使用 /{proxy+} 表示 /pets/pets/{petId}。此代理资源也可以引用任何其他 (现有或要添加的) 资源,例如 /food/{type}/{item}/toys/{type}/{item} 等,或者 /food/{type]/{subtype}/{item}/toys/{type}/{subtype}/{item} 等。后端开发人员确定资源层次结构,客户端开发人员负责了解此结构。API Gateway 会将客户端提交的内容传递到后端。

API 可以包含多个代理资源。例如,API 中允许包含以下代理资源。

/{proxy+} /parent/{proxy+} /parent/{child}/{proxy+}

如果代理资源具有非代理同级资源,则会从代理资源的表示形式中排除同级资源。在前面的示例中,/{proxy+} 是指除 /parent[/*] 资源之外的根资源下的任何资源。换言之,针对特定资源的方法请求优先于针对同一资源层次结构级别的通用资源的类似方法请求。

代理资源不能包含任何子资源。{proxy+} 后面的任何 API 资源都是冗余和不确定的资源。API 中不允许包含以下代理资源。

/{proxy+}/child /parent/{proxy+}/{child} /parent/{child}/{proxy+}/{grandchild+}

设置 HTTP 方法

API 方法请求通过 API Gateway 方法资源进行封装。要设置方法请求,您必须先实例化 Method 资源,设置至少一个 HTTP 方法和方法的授权类型。

API Gateway 与代理资源密切相关,支持 HTTP 方法 ANY。此 ANY 方法表示将在运行时提供的任何 HTTP 方法。它允许您将单个 API 方法设置用于 DELETEGETHEADOPTIONSPATCHPOSTPUT 支持的所有 HTTP 方法。

您也可以在非代理资源上设置 ANY 方法。通过将 ANY 方法与代理资源组合使用,即可获得适用于针对 API 的任何资源所支持的所有 HTTP 方法的单个 API 方法设置。此外,后端可以发展变化,而不会中断现有的 API 设置。

设置 API 方法之前,请考虑谁可以调用此方法。根据您的计划设置授权类型。对于开放式访问,将其设置为 NONE。要使用 IAM 权限,请将授权类型设置为 AWS_IAM。要使用基于 Lambda 函数的自定义授权方,请将此属性设置为 CUSTOM。要利用 Amazon Cognito 用户池,请将授权类型设置为 COGNITO_USER_POOLS

以下 AWS CLI 命令显示了如何针对指定资源 (6sxz2j) 为 ANY 动词创建使用 IAM 权限来控制其访问权限的方法请求。

aws apigateway put-method --rest-api-id vaz7da96z6 \ --resource-id 6sxz2j \ --http-method ANY \ --authorization-type AWS_IAM \ --region us-west-2

要创建使用不同授权类型的 API 方法请求,请参阅设置方法请求授权

设置方法请求参数

方法请求参数是一种客户端提供完成方法请求所需的输入数据或执行上下文的方式。方法参数可以是路径参数、标头或查询字符串参数。在方法请求设置期间,您必须声明必需的请求参数,使其可供客户端使用。对于非代理集成,您可以将这些请求参数转换为与后端要求兼容的形式。

例如,对于 GET /pets/{petId} 方法请求,{petId} 路径变量为必需的请求参数。您可在调用 AWS CLI 的 put-method 命令时声明此路径参数。下文对此进行了说明:

aws apigateway put-method --rest-api-id vaz7da96z6 \ --resource-id rjkmth \ --http-method GET \ --authorization-type "NONE" \ --region us-west-2 \ --request-parameters method.request.path.petId=true

如果参数不是必需的,则可在 request-parameters 中将其设置为 false。例如,如果 GET /pets 方法使用 type 的可选查询字符串参数和 breed 的可选标头参数,您可以使用以下 CLI 命令声明它们,假设 /pets 资源 id6sxz2j

aws apigateway put-method --rest-api-id vaz7da96z6 \ --resource-id 6sxz2j \ --http-method GET \ --authorization-type "NONE" \ --region us-west-2 \ --request-parameters method.request.querystring.type=false,method.request.header.breed=false

如果不使用这种缩写形式,您可以使用 JSON 字符串来设置 request-parameters 值:

'{"method.request.querystring.type":false,"method.request-header.breed":false}'

使用此设置,客户端可以按照类型查询宠物:

GET /pets?type=dog

客户端可以按照以下所示查询贵宾品种的狗:

GET /pets?type=dog breed:poodle

有关如何将方法请求参数映射到集成请求参数的信息,请参阅在 API Gateway 中设置 API 集成

设置方法请求模型

对于可在负载中获取输入数据的 API 方法,您可以使用模型。模型采用 JSON 架构草案 4 表示,描述了请求正文的数据结构。借助模型,客户端可以确定如何构建方法请求负载以作为输入。更重要的是,API Gateway 使用模型来验证请求生成开发工具包以及初始化用于在 API Gateway 控制台中设置集成的映射模板。有关如何创建模型的信息,请参阅模型和映射模板

根据内容类型,该方法负载可以具有不同格式。模型根据应用负载的媒体类型来编制索引。要设置方法请求模型,请在调用 AWS CLI put-method 命令时将 "<media-type>":"<model-name>" 格式的键/值对添加到 requestModels 映射。

例如,要在 PetStore 示例 API 的 POST /pets 方法请求的 JSON 负载上设置模型,您可以调用以下 AWS CLI 命令:

aws apigateway put-method \ --rest-api-id vaz7da96z6 \ --resource-id 6sxz2j \ --http-method POST \ --authorization-type "NONE" \ --region us-west-2 \ --request-models '{"application/json":"petModel"}'

其中,petModel 是描述宠物的 Model 资源的 name 属性值。实际架构定义采用 Model 资源的 schema 属性的 JSON 字符串值表示。

在 Java 或 API 的其他强类型开发工具包中,输入数据将强制转换为派生自架构定义的 petModel 类。使用请求模型,生成的开发工具包中的输入数据将强制转换为派生自默认 Empty 模型的 Empty 类。在这种情况下,客户端无法实例化正确的数据类以提供所需的输入。

设置方法请求授权

要控制哪些人可以调用 API 方法,您可在方法中配置授权类型。您可以使用此类型制定其中一个支持的授权方,包括 IAM 角色和策略 (AWS_IAM)、Amazon Cognito 用户池 (COGNITO_USER_POOLS) 或基于 Lambda 函数的自定义授权方 (CUSTOM)。对于开放式访问,API Gateway 控制台将 NONE 设置为默认值。

要使用 IAM 权限为 API 方法授予访问权限,请将 authorization-type 输入属性设置为 AWS_IAM。设置此选项后,API Gateway 会根据调用方的 IAM 用户的访问密钥标识符和私有密钥来验证调用方在请求中的签名。如果经过验证该用户有权调用此方法,将接受请求。否则将会拒绝请求,调用方会收到未经授权的错误响应。未成功调用该方法,除非调用方已被授予调用 API 方法的权限或调用方允许担任已授予此项权限的角色。调用方有权调用此方法以及由使用相同 AWS 账户的任何人创建的任何其他 API 方法,前提是调用方具有附加到其 IAM 用户的以下 IAM 策略:

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "execute-api:Invoke" ], "Resource": "arn:aws:execute-api:*:*:*" } ] }

有关更多信息,请参阅 使用 IAM 许可控制对 API 的访问

目前,此类策略仅可授予 API 所有者账户的 IAM 用户。对于使用不同 AWS 账户的用户,如果他们允许担任 API 所有者账户的角色,并且担任的角色具有执行 execute-api:Invoke 操作的适当权限,则可调用 API 方法。有关跨账户权限的信息,请参阅使用 IAM 角色

您可以使用 AWS CLI、AWS 开发工具包或 REST API 客户端 (例如 Postman),这将实施签名版本 4 签名流程

要使用自定义授权方来授予 API 方法的访问权限,请将 authorization-type 输入属性设置为 CUSTOM,并将 authorizer-id 输入属性设置为已存在的自定义授权方的 id 属性值。引用的自定义授权方可以是 TOKENREQUEST 类型。有关创建自定义授权方的信息,请参阅使用 API Gateway 自定义授权方

要使用 Amazon Cognito 用户池来授予 API 方法的访问权限,请将 authorization-type 输入属性设置为 COGNITO_USER_POOLS,并将 authorizer-id 输入属性设置为已创建的 COGNITO_USER_POOLS 授权方的 id 属性值。有关创建 Amazon Cognito 用户池授权方的信息,请参阅使用 Amazon Cognito 用户池

设置方法请求验证

您可在设置 API 方法请求时启用请求验证。首先,您需要创建请求验证程序

aws apigateway create-request-validator \ --rest-api-id 7zw9uyk9kl \ --name bodyOnlyValidator \ --validate-request-body \ --no-validate-request-parameters

此 CLI 命令创建仅限正文的请求验证程序。输出示例如下:

{ "validateRequestParameters": true, "validateRequestBody": true, "id": "jgpyy6", "name": "bodyOnlyValidator" }

使用此请求验证程序,您可在方法请求设置期间启用请求验证:

aws apigateway put-method \ --rest-api-id 7zw9uyk9kl --region us-west-2 --resource-id xdsvhp --http-method PUT --authorization-type "NONE" --request-parameters '{"method.request.querystring.type": false, "method.request.querystring.page":false}' --request-models '{"application/json":"petModel"}' --request-validator-id jgpyy6

要包含在请求验证中,必须将请求参数声明为必需参数。如果在请求验证中使用了该页面的查询字符串参数,则必须将前述示例的 request-parameters 映射指定为 '{"method.request.querystring.type": false, "method.request.querystring.page":true}'