Anotações e sintaxe dos frameworks do Cloud Endpoints

As anotações do Endpoints Frameworks descrevem a configuração, os métodos, os parâmetros e outros detalhes essenciais da API que definem as propriedades e o comportamento do ponto final.

Consulte o artigo Escrever e anotar código para obter informações sobre como adicionar anotações através de um projeto Maven. Maven Os artefactos dos Cloud Endpoints do App Engine são fornecidos para criar e compilar uma API de back-end e gerar uma biblioteca de cliente a partir dela.

A anotação que especifica a configuração e o comportamento em toda a API (afetando todas as classes expostas na API e todos os respetivos métodos expostos) é @Api. Todos os métodos públicos, não estáticos e não de ponte de uma classe anotada com @Api são expostos na API pública.

Se precisar de uma configuração especial da API para um método específico, pode usar opcionalmente @ApiMethod para definir a configuração por método. Configura estas anotações definindo vários atributos, conforme mostrado nas tabelas seguintes.

@Api: anotações ao nível da API

A anotação @Api configura toda a API e aplica-se a todos os métodos públicos de uma classe, a menos que seja substituída por @ApiMethod.

Para substituir uma anotação @Api específica para uma classe específica numa API, consulte @ApiClass e @ApiReference.

Importações necessárias

Para usar esta funcionalidade, precisa da seguinte importação:

import com.google.api.server.spi.config.Api;

Atributos

Atributos @Api Descrição Exemplo
audiences Obrigatório se a sua API exigir autenticação e se estiver a suportar clientes Android. Para mais informações, consulte o artigo IDs de clientes e públicos-alvo. audiences = {"1-web-apps.apps.googleusercontent.com", "2-web-apps.apps.googleusercontent.com"}
apiKeyRequired Opcional. Usado para restringir o acesso a pedidos que fornecem uma chave da API. apiKeyRequired = AnnotationBoolean.TRUE
authenticators Obrigatório se a sua API autenticar através do Firebase, do Auth0 ou de contas de serviço. Este atributo não é obrigatório se a sua API fizer a autenticação através de tokens de ID Google. Pode definir esta opção ao nível da API ou ao nível do método individual. Defina-o como {EspAuthenticator.class} ou pode escrever o seu próprio autenticador personalizado, conforme descrito em Interface Authenticator. authenticators = {EspAuthenticator.class}
backendRoot Descontinuado. Para publicar a sua API a partir de um caminho diferente, no ficheiro web.xml, altere o url-pattern na secção EndpointsServlet. <url-pattern>/example-api/*</url-pattern>
canonicalName Usado para especificar um nome diferente ou mais legível para a API na biblioteca cliente. Este nome é usado para gerar os nomes na biblioteca de cliente. A API de back-end continua a usar o valor especificado na propriedade name.

Por exemplo, se a sua API tiver a propriedade name definida como dfaanalytics, pode usar esta propriedade para especificar um nome canónico de DFA Group Analytics. As classes de cliente geradas contêm, então, o nome DfaGroupAnalytics.

Deve incluir os espaços relevantes entre os nomes. Estes são substituídos pela capitalização em camelo ou sublinhados adequados.
canonicalName = "DFA Analytics:"n
clientIds Obrigatório se a sua API usar autenticação. Lista de IDs de clientes para clientes autorizados a pedir tokens. Para mais informações, consulte o artigo IDs de clientes e públicos-alvo. clientIds = {"1-web-apps.apps.googleusercontent.com", "2-android-apps.apps.googleusercontent.com"}
defaultVersion Especifica se é usada uma versão predefinida se não for fornecida nenhuma no atributo version. defaultVersion = AnnotationBoolean.TRUE
description Uma breve descrição da API. Isto é exposto no serviço de deteção para descrever a sua API e, opcionalmente, também pode ser usado para gerar documentação. description = "Sample API for a simple game"
documentationLink O URL onde os utilizadores podem encontrar documentação sobre esta versão da API. Isto é apresentado no destaque "Saiba mais" do explorador de APIs na parte superior da página do explorador de APIs para permitir que os utilizadores saibam mais sobre o seu serviço. documentationLink = "http://link_to/docs"
issuers As configurações do emissor de JWT personalizadas. issuers = { @ApiIssuer(name = "auth0", issuer = "https://test.auth0.com/authorize", jwksUri = "https://test.auth0.com/.well-known/jwks.json") }
issuerAudiences Públicos-alvo para emissoras individuais. issuerAudiences = { @ApiIssuerAudience(name = "auth0", audiences = {"aud-1.auth0.com", "aud-2.auth0.com"}) }
limitDefinitions Opcional. Usado para definir quotas para a sua API. Consulte @ApiLimitMetric. limitDefinitions = { @ApiLimitMetric(name = "read-requests", displayName = "Read requests", limit = 1000)}
name O nome da API, que é usado como prefixo para todos os métodos e caminhos da API. O name valor:
  • Tem de começar com letras minúsculas
  • Tem de corresponder à expressão regular [a-z]+[A-Za-z0-9]*
Se não especificar name, é usado o myapi predefinido.
name = "foosBall"
namespace Configura o espaço de nomes para clientes gerados. Consulte @ApiNamespace. namespace=@ApiNamespace(ownerDomain="your-company.com", ownerName="YourCo", packagePath="cloud/platform")
root Descontinuado. Para publicar a sua API a partir de um caminho diferente, no ficheiro web.xml, altere o url-pattern na secção EndpointsServlet. <url-pattern>/example-api/*</url-pattern>
scopes Se não for fornecido, a predefinição é o âmbito do email (https://www.googleapis.com/auth/userinfo.email), que é necessário para o OAuth. Pode substituir esta opção para especificar mais âmbitos do OAuth 2.0, se quiser. No entanto, se definir mais do que um âmbito, tenha em atenção que a verificação do âmbito é aprovada se o token for gerado para qualquer um dos âmbitos especificados. Para exigir vários âmbitos, deve especificar um único String com um espaço entre cada âmbito. Para substituir os âmbitos especificados aqui para um método de API específico, especifique âmbitos diferentes na anotação @ApiMethod. scopes = {"ss0", "ss1 and_ss2"}
title O texto apresentado no API Explorer como o título da sua API e exposto nos serviços de descoberta e diretório. title = "My Backend API"
transformers Especifica uma lista de transformadores personalizados. Tenha em atenção que existe uma anotação alternativa (@ApiTransformer) que é preferível. Este atributo é substituído por @ApiTransformer. transformers = {BazTransformer.class}
version Especifica a versão do ponto final. Se não fornecer este valor, é usado o v1 predefinido. version = "v2"

Exemplo de@Api anotação

Esta anotação é colocada antes da definição da classe:

/** An endpoint class we are exposing. */
@Api(name = "myApi",
    version = "v1",
    namespace = @ApiNamespace(ownerDomain = "helloworld.example.com",
        ownerName = "helloworld.example.com",
        packagePath = ""))

IDs de cliente e públicos-alvo

Para a autenticação OAuth2, é emitida uma chave OAuth2 para um ID de cliente específico, o que significa que pode usar o ID de cliente para restringir o acesso às suas APIs. Quando regista uma aplicação Android na Google Cloud consola, cria um ID de cliente para a mesma. Este ID do cliente é o que pede um token OAuth2 à Google para fins de autenticação. Quando a API de back-end está protegida por autenticação, é enviada uma chave de acesso OAuth2 e aberta pelos Endpoints. O ID de cliente é extraído da chave e, em seguida, o ID é comparado com a lista de IDs de clientes aceitáveis declarados do back-end (a lista clientIds).

Se quiser que a API Endpoints autentique os autores da chamada, tem de fornecer uma lista de clientIds que têm autorização para pedir tokens. Esta lista deve consistir em todos os IDs de cliente que obteve através do Google Cloud console para os seus clientes Web ou Android. Isto significa que os clientes têm de ser conhecidos no momento da criação da API. Se especificar uma lista vazia, {}, nenhum cliente pode aceder aos métodos protegidos pela autenticação.

Se usar o atributo clientIds e quiser testar chamadas autenticadas para a sua API através do Google API Explorer, tem de fornecer o respetivo ID de cliente na lista de clientIds: o valor a usar é com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID.

Acerca dos públicos-alvo

A clientIdslistaprotege a API de back-end de clientes não autorizados. No entanto, é necessária uma proteção adicional para proteger os clientes, para que o respetivo token de autorização funcione apenas para a API de back-end pretendida. Para clientes Android, este mecanismo é o atributo audiences, no qual especifica o ID de cliente da API de back-end.

Tenha em atenção que, quando cria um Google Cloud projeto da consola, é criado automaticamente um ID do cliente predefinido e atribuído-lhe um nome para utilização pelo projeto. Quando carrega a API de back-end para o App Engine, este usa esse ID de cliente. Este é o ID de cliente Web mencionado na secção Autenticação de API.

@ApiMethod: anotações ao nível do método

A anotação @ApiMethod é usada para fornecer uma configuração da API diferente das predefinições fornecidas pelas anotações @Api ou @ApiClass. Tenha em atenção que isto é opcional: todos os métodos públicos, não estáticos e não de ponte numa classe com uma anotação @Api são expostos na API, quer tenham uma anotação @ApiMethod ou não.

Os atributos nesta anotação permitem-lhe configurar detalhes de um único método de API. Se o mesmo atributo for especificado em @Api e @ApiMethod, @ApiMethod substitui.

Importações necessárias

Para usar esta funcionalidade, precisa das seguintes importações:

import com.google.api.server.spi.config.AnnotationBoolean;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiMethod.HttpMethod;

Atributos

Atributos @ApiMethod Descrição Exemplo
apiKeyRequired Opcional. Usado para restringir o acesso a pedidos que fornecem uma chave da API. apiKeyRequired = AnnotationBoolean.TRUE
audiences Forneça esta informação se quiser substituir a configuração em @API. Para mais informações, consulte o artigo IDs de clientes e públicos-alvo. audiences = {"1-web-apps.apps.googleusercontent.com", "2-web-apps.apps.googleusercontent.com"}
authenticators Obrigatório se a sua API autenticar através do Firebase, do Auth0 ou de contas de serviço, e não tiver definido este atributo ao nível da API. Este atributo não é obrigatório se a sua API fizer a autenticação através de tokens de ID Google. Defina-o como {EspAuthenticator.class} ou pode escrever o seu próprio autenticador personalizado, conforme descrito em Interface Authenticator authenticators = {EspAuthenticator.class}
clientIds Lista de IDs de clientes para clientes autorizados a pedir tokens. Obrigatório se a sua API usar autenticação. clientIds = {"1-web-apps.apps.googleusercontent.com", "2-android-apps.apps.googleusercontent.com"}
httpMethod O método HTTP a usar. Se não definir esta opção, é escolhida uma predefinição com base no nome do método. httpMethod = HttpMethod.GET
issuerAudiences Forneça esta informação se quiser substituir a configuração em @Api. issuerAudiences = { @ApiIssuerAudience(name = "auth0", audiences = {"aud-1.auth0.com", "aud-2.auth0.com"}) }
metricCosts Opcional. Indica que o método tem um limite de quota. Atribui a anotação @ApiMetricCost a metricCosts. Também tem de especificar o atributo limitDefinitions para definir a quota na anotação @Api. A anotação @ApiMetricCostaceita os seguintes atributos:
  • name: um nome que especificou na anotação ApiLimitMetric.
  • cost: um número inteiro que especifica o custo de cada pedido. O custo permite que os métodos consumam a diferentes taxas a partir da mesma quota. Por exemplo, se uma quota tiver um limite de 1000 e um custo de 1, a aplicação de chamadas pode fazer 1000 pedidos por minuto antes de exceder o limite. Com um custo de 2 para a mesma quota, uma aplicação de chamadas só pode fazer 500 pedidos por minuto antes de exceder o limite.
metricCosts = { @ApiMetricCost(name = read-requests", cost = 1) }
name O nome deste método na biblioteca de cliente gerada. Este é automaticamente precedido do nome da API para criar um nome exclusivo para o método. O name valor:
  • Tem de começar com letras minúsculas
  • Tem de corresponder à expressão regular [a-z]+[A-Za-z0-9]*
Se não especificar name, é usado o myapi predefinido.
name = "foosBall.list"
path O caminho do URI a usar para aceder a este método. Se não definir esta opção, é usado um caminho predefinido com base no nome do método Java. Se planear adicionar a gestão de APIs, não inclua uma barra invertida no final do caminho. path = "foos"
scopes Especifique um ou mais âmbitos do OAuth 2.0, um dos quais é necessário para chamar este método. Se definir scopes para um método, substitui a definição na anotação @Api. Se definir mais do que um âmbito, tenha em atenção que a verificação do âmbito é aprovada se o token for gerado para qualquer um dos âmbitos especificados. Para exigir vários âmbitos, especifique um único String com um espaço entre cada âmbito. scopes = {"ss0", "ss1 and_ss2"}

Exemplo de anotação @ApiMethod

Esta anotação é colocada antes da definição do método numa classe:

/** A simple endpoint method that takes a name and says Hi back. */
@ApiMethod(
    name = "sayHiUser",
    httpMethod = ApiMethod.HttpMethod.GET)
public MyBean sayHiUser(@Named("name") String name, User user)
    throws OAuthRequestException, IOException {
  MyBean response = new MyBean();
  response.setData("Hi, " + name + "(" + user.getEmail() + ")");

  return response;
}

Os métodos que usam uma entidade como parâmetro devem usar HttpMethod.POST (para operações de inserção) ou HttpMethod.PUT (para operações de atualização):

@ApiMethod(
    name = "mybean.insert",
    path = "mybean",
    httpMethod = ApiMethod.HttpMethod.POST
)
public void insertFoo(MyBean foo) {
}

@Named

A anotação @Named é obrigatória para todos os parâmetros de tipo não de entidade transmitidos para métodos do lado do servidor. Esta anotação indica o nome do parâmetro no pedido que é injetado aqui. Um parâmetro que não esteja anotado com @Named é injetado com o objeto de pedido completo.

Importações necessárias

Para usar esta funcionalidade, precisa das seguintes importações:

import javax.inject.Named;

Este exemplo mostra a utilização de @Named:

/** A simple endpoint method that takes a name and says Hi back. */
@ApiMethod(name = "sayHi")
public MyBean sayHi(@Named("name") String name) {
  MyBean response = new MyBean();
  response.setData("Hi, " + name);

  return response;
}

onde @Named especifica que apenas o parâmetro id é injetado no pedido.

@ApiLimitMetric

Esta secção descreve as anotações necessárias para definir quotas para a sua API. Consulte o artigo Configurar quotas para ver todos os passos necessários para configurar uma quota.

Atribui a anotação @ApiLimitMetric ao atributo limitDefinitions das anotações ao nível da API. Também tem de adicionar @ApiMetricCost às anotações @ApiMethod para cada método ao qual quer aplicar uma quota.

Importações necessárias

Para usar esta funcionalidade, precisa da seguinte importação:

import com.google.api.server.spi.config.ApiLimitMetric;

Atributos

Atributos de @ApiLimitMetric

Descrição
nome O nome da quota. Normalmente, este é o tipo de pedido (por exemplo, "read-requests" ou "write-requests") que identifica exclusivamente a quota
displayName O texto apresentado para identificar a quota no separador Quotas na página Endpoints > Serviços da Google Cloud consola. Este texto também é apresentado aos consumidores da sua API na página Quotas de IAM e administrador e API e serviços. O nome a apresentar tem de ter um máximo de 40 carateres.
Para fins de legibilidade, o texto "por minuto por projeto" é automaticamente anexado ao nome a apresentar nas páginas Quotas.
Para manter a consistência com os nomes a apresentar dos serviços Google apresentados nas páginas de Quotas que os consumidores da sua API veem, recomendamos o seguinte para o nome a apresentar:
  • Use "Pedidos" quando tiver apenas uma métrica.
  • Quando tem várias métricas, cada uma deve descrever o tipo de pedido e conter a palavra "pedidos" (por exemplo, "Pedidos de leitura" ou "Pedidos de escrita").
  • Use "unidades de quota" em vez de "pedidos" quando qualquer um dos custos desta quota for superior a 1.
limite Um valor inteiro que é o número máximo de pedidos por minuto por projeto de consumidor para a quota.

Exemplo

limitDefinitions = {
      @ApiLimitMetric(
        name = "read-requests",
        displayName = "Read requests",
        limit = 1000),
      @ApiLimitMetric(
        name = "write-requests",
        displayName = "Write requests",
        limit = 50),
    }

@ApiNamespace

A anotação @ApiNamespace faz com que as bibliotecas de cliente geradas tenham o espaço de nomes que especificar, em vez de um espaço de nomes predefinido criado durante a geração da biblioteca de cliente.

Por predefinição, se não usar esta anotação, o espaço de nomes usado é o inverso de your-project-id.appspot.com. Ou seja, o caminho do pacote é com.appspot.your-project-id.yourApi.

Pode alterar o espaço de nomes predefinido fornecendo a anotação @ApiNamespace na anotação @Api:

/** An endpoint class we are exposing. */
@Api(name = "myApi",
    version = "v1",
    namespace = @ApiNamespace(ownerDomain = "helloworld.example.com",
        ownerName = "helloworld.example.com",
        packagePath = ""))

Defina o atributo ownerDomain para o domínio da sua empresa e ownerName para o nome da sua empresa, por exemplo, your-company.com. O inverso de ownerDomain é usado para o caminho do pacote: com.your-company.yourApi.

Opcionalmente, pode usar o atributo packagePath para fornecer um âmbito mais alargado. Por exemplo, se definir packagePath como cloud, o caminho do pacote usado na biblioteca de cliente é com.your-company.cloud.yourApi. Pode adicionar mais valores ao caminho do pacote fornecendo o delimitador /: packagePath="cloud/platform".

@Nullable

Esta anotação indica que um parâmetro de um método é opcional (e, por isso, um parâmetro de consulta). @Nullable só pode ser usado com parâmetros @Named.

@ApiClass

Numa API de várias classes, pode usar @ApiClass para especificar propriedades diferentes para uma determinada classe, substituindo as propriedades equivalentes na configuração @Api. Consulte o artigo Usar @ApiClass para propriedades que podem diferir entre classes para uma descrição completa desta anotação.

@ApiReference

Numa API de várias classes, pode usar @ApiReference para fornecer um método alternativo de herança de anotações. Consulte a secção Usar a herança de @ApiReference para uma descrição completa desta anotação.

@ApiResourceProperty

@ApiResourceProperty permite controlar a forma como as propriedades dos recursos são expostas na API. Pode usá-lo num getter ou num setter de propriedade para omitir a propriedade de um recurso da API. Também pode usá-lo no próprio campo, se o campo for privado, para o expor na API. Também pode usar esta anotação para alterar o nome de uma propriedade num recurso da API.

Importações necessárias

Para usar esta funcionalidade, precisa das seguintes importações:

import com.google.api.server.spi.config.ApiResourceProperty;
import com.google.api.server.spi.config.AnnotationBoolean;

Atributos

Atributos @ApiResourceProperty Descrição Exemplo
ignored Se estiver definido como AnnotationBoolean.TRUE, omite a propriedade. Se não for especificado ou for definido como AnnotationBoolean.FALSE, a propriedade não é omitida. @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
name Se for fornecido, especifica o nome da propriedade a ser exposto na API. @ApiResourceProperty(name = "baz")

Exemplo de classe com @ApiResourceProperty

O fragmento seguinte mostra uma classe com getters de propriedades anotados com @ApiResourceProperty:


class Resp {
  private String foobar = "foobar";
  private String bin = "bin";

  @ApiResourceProperty
  private String visible = "nothidden";

  @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
  public String getBin() {
    return bin;
  }

  public void setBin(String bin) {
    this.bin = bin;
  }

  @ApiResourceProperty(name = "baz")
  public String getFoobar() {
    return foobar;
  }

  public void setFoobar(String foobar) {
    this.foobar = foobar;
  }
}

public Resp getResp() {
  return new Resp();
}

No fragmento do código anterior, @ApiResourceProperty é aplicado ao getter getBin para a propriedade bin, com a definição do atributo ignored a indicar aos Frameworks de Endpoints para omitir esta propriedade no recurso da API.

@ApiResourceProperty também é aplicado ao campo privado visible, que não tem getter nem setter. A utilização desta anotação expõe este campo como uma propriedade no recurso da API.

No mesmo fragmento, @ApiResourceProperty também é aplicado a um getter diferente, getFoobar, que devolve um valor de propriedade para a propriedade foobar. O atributo name nesta anotação indica aos Frameworks de Endpoints para alterar o nome da propriedade no recurso da API. O valor da propriedade em si permanece inalterado.

No fragmento de exemplo anterior, a representação JSON de um objeto Resp tem um aspeto semelhante ao seguinte:

{"baz": "foobar", "visible": "nothidden"}

@ApiTransformer

A anotação @ApiTransformer personaliza a forma como um tipo é exposto nos Endpoints através da transformação para e a partir de outro tipo. (O transformador especificado tem de ser uma implementação de com.google.api.server.spi.config.Transformer.)

A utilização da anotação @ApiTransformer numa classe é a forma preferencial de especificar um transformador. No entanto, em alternativa, pode especificar o transformador personalizado no atributo transformer da anotação @Api.

Importações necessárias

Para usar esta funcionalidade, precisa da seguinte importação:

import com.google.api.server.spi.config.ApiTransformer;

Exemplo de classe com @ApiTransformer

O seguinte fragmento mostra uma classe anotada com @ApiTransformer:


@ApiTransformer(BarTransformer.class)
public class Bar {
  private final int x;
  private final int y;

  public Bar(int x, int y) {
    this.x = x;
    this.y = y;
  }

  public int getX() {
    return x;
  }

  public int getY() {
    return y;
  }
}

Esta turma é transformada pela turma BarTransformer.

Classe de transformador de pontos finais de exemplo

O fragmento seguinte mostra uma classe de transformador de amostra denominada BarTransformer. Este é o transformador referenciado por @ApiTransformer no fragmento anterior:

public class BarTransformer implements Transformer<Bar, String> {
  public String transformTo(Bar in) {
    return in.getX() + "," + in.getY();
  }

  public Bar transformFrom(String in) {
    String[] xy = in.split(",");
    return new Bar(Integer.parseInt(xy[0]), Integer.parseInt(xy[1]));
  }
}

Supondo que existe um objeto com uma propriedade bar do tipo Bar, sem o transformador anterior, o objeto é representado da seguinte forma:

{"bar": {"x": 1, "y": 2}}

Com o transformador, o objeto é representado da seguinte forma:

{"bar": "1,2"}