装饰器

Python 版 Cloud Endpoints Frameworks 装饰器描述定义端点的属性和行为的 API 配置、方法、参数以及其他重要细节。

本页面详细介绍可用的装饰器。如需了解如何使用装饰器来创建 API,请参阅以下内容:

定义 API (@endpoints.api)

您可以通过为 @endpoints.api 提供多个参数来定义 API。下表介绍了可用的参数:

@endpoints.api 参数 说明 示例
allowed_client_ids 如果您的 API 使用身份验证,则该参数是必需的。允许请求令牌的客户端的 ID 列表。如需了解详情,请参阅允许的客户端 ID 和目标设备 allowed_client_ids=['1-web-apps.apps.googleusercontent.com','2-android-apps.apps.googleusercontent.com', endpoints.API_EXPLORER_CLIENT_ID]
api_key_required 可选。用于限制访问权限,只有提供 API 密钥的请求具有访问权限。 api_key_required=True
audiences 如果您的 API 需要身份验证并且您支持 Android 客户端,则该参数是必需的。对于 Google ID 令牌,这可以是请求这些令牌的客户端 ID 列表。如果令牌是由第三方身份验证提供商(例如 Auth0)颁发的,则这必须是从身份验证颁发者名称到目标设备列表的字典映射。如需了解详情,请参阅允许的客户端 ID 和目标设备 audiences=['1-web-apps.apps.googleusercontent.com']audiences={"auth0": ["aud-1.auth0.com", "aud-2.auth0.com"]}
base_path 可选。用于从指定路径提供 API。如果指定此参数,您还必须更改 app.yaml 文件中的 handlers 部分。 请参阅通过其他路径提供 API
canonical_name 可选。用于在客户端库中为 API 指定不同或者更易理解的名称。该名称用于生成客户端库中的名称,而后端 API 会继续使用 name 属性中指定的值。

例如,如果您的 API 的 name 设置为 dfaanalytics,则您可以使用该属性来指定 DFA Group Analytics 这样一个规范化名称,生成的客户端类就将包含名称 DfaGroupAnalytics

您应该如同所示在名称之间添加相关空格;这些空格会被相应的驼峰式大小写格式或下划线替换。
canonical_name='DFA Analytics'
description API 的简短说明。该属性在发现服务中公开,用于描述您的 API,您也可以选择使用该属性生成文档,如生成客户端库中所述。 description='Sample API for a simple game'
documentation 可选。用户可以在其中找到此版本 API 的相关文档的网址。此链接显示在 API Explorer 页面顶部的 API Explorer “了解详情”突出显示部分中,让用户能够了解您的服务。 documentation='http://link_to/docs'
hostname App Engine 应用的主机名。Endpoints Frameworks 命令行工具在生成 Discovery 文档或 OpenAPI 文档时,会使用您在此处指定的值。如果您没有在此处指定主机名,则必须在 app.yaml 文件的 application 字段中指定主机名,或者在部署 App Engine 应用时指定项目 ID。 hostname='your_app_id.appspot.com'
issuers 可选。自定义的 JWT 颁发者配置。这应该是从颁发者名称到 endpoints.Issuer 对象的字典映射。 issuers={"auth0": endpoints.Issuer("https://test.auth0.com", "https://test.auth0.com/.well-known/jwks.json")}
name 必填。API 的名称,用作所有 API 方法和路径的前缀。name 值:
  • 必须以小写字母开头。
  • 必须匹配正则表达式 [a-z]+[A-Za-z0-9];也就是说,名称的其余部分可以由大写字母、小写字母或数字组成。
如需在单个服务中部署多个 API,所有 API 名称必须匹配正则表达式 [a-z][a-z0-9]{0,39},也就是说,名称必须以小写字母开头,其余字符必须是小写字母或数字,最大长度为 40 个字符。
name='yourApi'name='yourapi'
limit_definitions 可选。用于定义 API 的配额。如需了解详情,请参阅 limit_definitions
owner_domain 可选。拥有 API 的实体的域名。与 owner_name 一起使用,以便在为此 API 生成客户端库时提供关于正确命名客户端库的提示。如果提供了该参数值,软件包路径为 owner_domain 的反转值加上 package_path。默认情况下使用的是 appid.apppost.com owner_domain='your-company.com'
owner_name 可选。拥有 API 的实体的名称。与 owner_domain 一起使用,以便在为此 API 生成客户端库时提供关于正确命名客户端库的提示。 owner_name='Your-Company'
package_path 可选。用于进一步确定此 API 所属“软件包”的范围,其值由 / 分隔以便指定 API 的逻辑分组。

例如,指定 cloud/platform 会使客户端库路径设置为 cloud/platform/<ApiName>,并使客户端库软件包设置为 cloud.plaform.<ApiName>
package_path='cloud/platform'
scopes 如果未提供值,则默认为电子邮件范围 (https://www.googleapis.com/auth/userinfo.email),OAuth 需要该参数。您可以根据需要替换该值,以指定更多 OAuth 2.0 范围。您还可以为特定 API 方法替换此处指定的范围,方法是在 @endpoints.method 装饰器中指定不同的范围。不过请注意,如果您定义了多个范围,那么为任何指定范围生成令牌,都会让整个范围检查成功通过。如果需要多个范围,请指定一个字符串,并在各个范围之间添加空格加以间隔。 scopes=['ss0', 'ss1 and_ss2']
title 可选。该文本作为 API 的标题显示在 API Explorer 中,并在发现服务和目录服务中公开。 title='My Backend API'
version 必需。指定您的 Cloud Endpoints 版本。该值将显示在 API 的路径中。如果您指定的版本字符串与 SemVer 标准兼容,则在部署您的 API 时,只有主要版本号会显示在该 API 的路径中。例如,一个名为 echo 且版本为 2.1.0 的 API 将具有类似 /echo/v2 的路径。如果您将 echo API 更新到版本 2.2.0 并部署向后兼容的更改,则路径仍为 /echo/v2。这样一来,您可以在进行向后兼容的更改时更新 API 版本号,而不会破坏客户端的现有路径。但是,如果您将 echo API 更新到版本 3.0.0(因为要部署重大更改),路径将更改为 /echo/v3 version='v1'version='2.1.0'

limit_definitions

如需为您的 API 定义配额,请将可选 limit_definitions 参数指定为 @endpoints.api。要配置配额,您还必须执行以下操作:

  • 安装 Endpoints Frameworks 客户端库的 2.4.5 版本或更高版本。
  • 对于要应用配额的每个方法,将 metric_costs 参数添加到其方法装饰器中。

如需了解设置配额所需的所有步骤,请参阅配置配额

您可以指定一个或多个 LimitDefinition 实例的列表,类似于以下内容:

quota_limits = [
              endpoints.LimitDefinition(
                "name",
                "Display name",
                limit)
]

每个 LimitDefinition 实例必须具有以下值:

元素 说明
name API 请求计数器的名称。通常,这是唯一标识配额的请求类型(例如,“read-requests”或“write-requests”)。
Display name

显示的文本用于标识 Endpoints > 服务页面上配额标签页中的配额。此文本还会显示在“IAM 和管理员”与“API 和服务”的配额页面上,供 API 的使用方查看。显示名不得超过 40 个字符。

为确保可读性,文本“per minute per project”会自动附加到“配额”页面上的显示名末尾。 为了与 API 使用方在“配额”页面上看到的 Google 服务的显示名保持一致,我们针对显示名提出以下建议:

  • 只有一个指标时,请使用“Requests”。
  • 如果您有多个指标,则每个指标都应描述请求的类型并包含“requests”一词(例如“Read requests”或“Write requests”)。
  • 当该配额的任何费用大于 1 时,请使用“Quota units”,而不是“Requests”。

limit 一个整数值,是指每个使用方项目每分钟针对配额发出的请求次数上限。

示例

quota_limits = [
  endpoints.LimitDefinition('read-requests', 'Read Requests', 1000),
  endpoints.LimitDefinition('list-requests', 'List Requests', 100),
  endpoints.LimitDefinition('write-requests', 'Write Requests', 50)
]

@endpoints.api(name='bookstore',
               version='v1',
               limit_definitions=quota_limits)

允许的客户端 ID 和目标设备

对于 OAuth2 身份验证,会向特定客户端 ID 发出 OAuth2 令牌,这意味着您可以使用该客户端 ID 来限制对您的 API 的访问。当您在 Google Cloud 控制台中注册 Android 应用时, 您需要为其创建客户端 ID该客户端 ID 会出于身份验证目的,向 Google 请求 OAuth2 令牌。如果后端 API 受身份验证保护,适用于 App Engine 的 Endpoints Frameworks 会发送并打开 OAuth2 访问令牌,系统从该令牌中提取客户端 ID,然后将该 ID 与后端声明的可接受客户端 ID 列表(allowed_client_ids 列表)进行比对。

allowed_client_ids 列表应包含您通过 Google Cloud 控制台为您的 Web、Android 和其他客户端应用获取的所有客户端 ID。这意味着客户端必须在构建 API 时就已知。如果您指定空列表,则所有客户端均不可访问该 API。

请注意,在要检查是否有正确身份验证的每个 API 方法中,您必须调用 endpoints.get_current_user()。如需了解更多信息,请参阅对用户进行身份验证

如果您使用 allowed_client_ids 参数,并且希望使用 API Explorer 测试经过身份验证的 API 调用,则必须在 allowed_client_ids 列表中提供其客户端 ID,方法是指定常数 endpoints.API_EXPLORER_CLIENT_ID。请注意,如果 allowed_client_ids 仅包含 endpoints.API_EXPLORER_CLIENT_ID,并且您部署了自己的 API,则该 API 仍然会被公开,并且可以使用 API Explorer 公开进行访问。

关于目标设备

allowed_client_ids 列表可保护后端 API 免遭未经授权的客户端访问。但您仍需要进一步保护客户端,以使其身份验证令牌仅用于预期的后端 API。对于 Android 客户端,该机制是 audiences 参数,您可以在该参数中指定后端 API 的客户端 ID。

请注意,在创建 Google Cloud 控制台项目时,系统会自动创建并命名一个默认客户端 ID 以供项目使用。当您将后端 API 上传到 App Engine 时,它会使用该客户端 ID。这是 API 身份验证中提到的 Web 客户端 ID。

第三方身份验证令牌颁发者

如果您的应用接受的身份验证令牌不是 Google ID 令牌,而是由第三方发布者颁发的令牌,则您需要在 @endpoints.api 中正确设置 audiencesissuers 参数,以提供有关第三方颁发者的信息。例如:

@endpoints.api(
        audiences={'auth0': ['aud-1.auth0.com', 'aud-2.auth0.com']},
        issuers={'auth0': endpoints.Issuer('https://test.auth0.com',
                                           'https://test.auth0.com/.well-known/jwks.json')})
class GreetingApi(remote.Service):

定义 API 方法 (@endpoints.method)

您可以使用 @endpoints.api 为整个 API 设定 audiencesscopesallowed_client_ids 设置,也可以使用 @endpoints.method 为某个方法设定这些设置。如果在 API 级别和方法级别都指定了这些设置,则以方法级别的设置为准。

如需在 API 中创建方法,请使用 @endpoints.method 装饰相应的 Python 方法,并提供参数以配置方法的使用。例如,您应指定要使用的请求和响应 Message 类。

下表列出了可用的参数:

@endpoints.method 参数 说明 示例
allowed_client_ids 此设置将替换 @endpoints.api 中指定的等效特性。如需了解详情,请参阅允许的客户端 ID 和目标设备 ['1-web-apps.apps.googleusercontent.com', '2-android-apps.apps.googleusercontent.com']
api_key_required 可选。用于将访问权限限制于那些提供了 API 密钥的请求。 api_key_required=True
audiences 将替换 @endpoints.api 中指定的等效参数。如需了解详情,请参阅允许的客户端 ID 和目标设备 ['1-web-apps.apps.googleusercontent.com']
metric_costs 可选。表示该方法具有配额限制。这是一个具有以下键值对的字典:
  • name:您在 API 装饰器的 limit_definitions 参数中指定的名称。
  • cost:一个整数,用于指定每个请求的耗费。耗费的值让方法按不同的速率消耗同一配额。例如,如果配额上限为 1000 且耗费为 1,那么在超出该上限之前,调用方应用每分钟可发出 1000 个请求。对于相同配额,如果费用为 2,则在超出上限之前,调用方应用每分钟只能发出 500 个请求。
metric_costs={'read-requests': 1}
http_method 要使用的 HTTP 方法。如果未设置此参数,则默认使用 'POST' 'GET'
name 此方法的替代名称。name 值:
  • 必须以小写字母开头。
  • 必须匹配正则表达式 [a-z]+[A-Za-z0-9]*
'yourApi'
path 用于访问此方法的 URI 路径。如果未设置此参数,则使用 Python 方法的名称。如果您计划添加 API 管理,请勿在路径中包含尾部斜杠。 'yourapi/path'
Request Message 需要在方法调用中使用的 Google Protocol RPC Request Message 类。或者,您可以提供类的名称。 YourRequestClass
Response Message 需要在方法调用中使用的 Google Protocol RPC Response Message 类。或者,您可以提供类的名称。 YourResponseClass

ResourceContainer 用于路径或查询字符串参数

如果请求包含路径或查询字符串参数,则您不能使用创建 API 中所述的简单 Message 类,而必须使用 ResourceContainer 类,具体如下所示:

  1. 定义一个 Message 类,其中包含将在请求正文中传递的所有参数。如果请求正文中没有任何参数,则不需要定义 Message 类,使用 message_types.VoidMessage 即可。例如:

    class Greeting(messages.Message):
        """Greeting that stores a message."""
    
        message = messages.StringField(1)
  2. 使用您在上一步中定义的 Message 类定义 ResourceContainer 作为第一个参数。在后续参数中指定路径和查询字符串参数。例如:

    MULTIPLY_RESOURCE = endpoints.ResourceContainer(
        Greeting,
        times=messages.IntegerField(2, variant=messages.Variant.INT32, required=True),

    其中第一个参数是用于请求正文中数据的 Message 类,times 是请求附带的路径或字符串中应使用的数字。

  3. ResourceContainer 提供给处理请求的方法,在第一个参数中,替换原本应在该位置提供的请求 Message 类。此代码段将同时显示 ResourceContainerendpoints.method

    # This ResourceContainer is similar to the one used for get_greeting, but
    # this one also contains a request body in the form of a Greeting message.
    MULTIPLY_RESOURCE = endpoints.ResourceContainer(
        Greeting,
        times=messages.IntegerField(2, variant=messages.Variant.INT32, required=True),
    )
    
    @endpoints.method(
        # This method accepts a request body containing a Greeting message
        # and a URL parameter specifying how many times to multiply the
        # message.
        MULTIPLY_RESOURCE,
        # This method returns a Greeting message.
        Greeting,
        path="greetings/multiply/{times}",
        http_method="POST",
        name="greetings.multiply",
    )
    def multiply_greeting(self, request):
        return Greeting(message=request.message * request.times)
    
  4. 如上所示添加 path 参数,以包含您的 API。

  5. 如果您的 ResourceContainer 包含一个必需参数,则客户端请求必须将其包含在查询字符串(例如 yourApi?times=2)或网址路径(例如 yourApi/2)中。但是,为了使 API 通过网址路径接收参数值,您还必须将参数名称添加到 API 路径中(如 path='yourApi/{times} 中的 {times} 参数所示)。

后续步骤