Anotações e sintaxe do Cloud Endpoints Frameworks

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

Consulte Como escrever e fazer anotações sobre o código para informações sobre como adicionar anotações usando um projeto Maven. Os artefatos do Maven App Engine Cloud Endpoints são fornecidos para desenvolver e criar 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 (que afeta todas as classes expostas na API e todos os métodos expostos) é @Api. Todos os métodos públicos, não estáticos e não interligadores de uma classe anotados com @Api ficam expostos na API pública.

Se você precisar de configuração especial da API para um método específico, terá a opção de usar @ApiMethod para definir a configuração para cada método. Configure essas anotações definindo vários atributos, conforme mostrado nas tabelas a seguir.

@Api: anotações com escopo da API

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

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

Importações obrigatórias

Para usar esse recurso, é necessária a seguinte importação:

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

Atributos

Atributos de @Api Descrição Exemplo
audiences Obrigatório se a API exigir autenticação e se você oferecer suporte a clientes Android. Para mais informações, consulte IDs do cliente 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 solicitações que fornecem uma chave de API. apiKeyRequired = AnnotationBoolean.TRUE
authenticators Obrigatório se a API autentica usando Firebase, Auth0 ou contas de serviço. Este atributo não é obrigatório se a API autentica usando tokens de ID do Google. É possível definir isso no nível da API ou no nível do método individual. Defina-o como {EspAuthenticator.class} ou escreva seu próprio autenticador personalizado, conforme descrito no Autenticador de interface. authenticators = {EspAuthenticator.class}
backendRoot Uso suspenso. Para exibir a API a partir de um caminho diferente, no seu arquivo web.xml, altere o url-pattern na seção EndpointsServlet. <url-pattern>/example-api/*</url-pattern>
canonicalName Usado para especificar um nome distinto ou mais legível para a API na biblioteca de cliente. Esse 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 sua API tiver name definido como dfaanalytics, você pode usar essa propriedade para especificar um nome canônico de DFA Group Analytics; as classes de cliente geradas, então, conteriam o nome DfaGroupAnalytics.

É preciso incluir os espaços relevantes entre os nomes; eles serão substituídos pelos caracteres mistos de maiúsculas e minúsculas ou por caracteres de sublinhado.
canonicalName = "DFA Analytics:"n
clientIds Obrigatório se a API usa autenticação. Lista de IDs de clientes que solicitam tokens. Para mais informações, consulte IDs do cliente e públicos-alvo. clientIds = {"1-web-apps.apps.googleusercontent.com", "2-android-apps.apps.googleusercontent.com"}
defaultVersion Especifica se uma versão padrão será usada se nenhuma for fornecida no atributo version. defaultVersion = AnnotationBoolean.TRUE
description Uma breve descrição da API. Ela fica exposta no serviço de descoberta para descrever a API e pode, opcionalmente, ser usada para gerar documentação. description = "Sample API for a simple game"
documentationLink O URL em que os usuários encontram a documentação sobre essa versão da API. Isso é exibido no destaque "Saiba mais", na parte superior da página do API Explorer, para que os usuários conheçam seu serviço. documentationLink = "http://link_to/docs"
issuers As configurações personalizadas do emissor JWT. issuers = { @ApiIssuer(name = "auth0", issuer = "https://test.auth0.com/authorize", jwksUri = "https://test.auth0.com/.well-known/jwks.json") }
issuerAudiences Públicos-alvo de emissores individuais. issuerAudiences = { @ApiIssuerAudience(name = "auth0", audiences = {"aud-1.auth0.com", "aud-2.auth0.com"}) }
limitDefinitions Opcional. Usado para definir as cotas para sua API. Consulte @ApiLimitMetric. limitDefinitions = { @ApiLimitMetric(name = "read-requests", displayName = "Read requests", limit = 1000)}
name O nome da API usado como prefixo em todos os métodos e caminhos da API. O valor name:
  • precisa começar com caractere minúsculo;
  • precisa corresponder à expressão regular [a-z]+[A-Za-z0-9]*
Se você não especificar name, o padrão myapi será usado.
name = "foosBall"
namespace Configura a atribuição do namespace para clientes gerados. Veja @ApiNamespace. namespace=@ApiNamespace(ownerDomain="your-company.com", ownerName="YourCo", packagePath="cloud/platform")
root Uso suspenso. Para exibir a API a partir de um caminho diferente, no seu arquivo web.xml, altere o url-pattern na seção EndpointsServlet. <url-pattern>/example-api/*</url-pattern>
scopes Se não for fornecido, o padrão é o escopo do e-mail (https://www.googleapis.com/auth/userinfo.email), que é obrigatório para o OAuth. É possível substituí-lo para especificar mais escopos OAuth 2.0, se você quiser. No entanto, se mais de um escopo for definido, a verificação deles será aprovada se o token for criado para qualquer um dos escopos especificados. Para exigir vários escopos, especifique uma única Stringcom um espaço entre cada escopo. Para modificar os escopos especificados aqui para determinado método da API, determine escopos diferentes na anotação @ApiMethod. scopes = {"ss0", "ss1 and_ss2"}
title O texto exibido no API Explorer como título da API e exposto na descoberta e nos serviços de diretório. title = "My Backend API"
transformers Especifica uma lista de transformadores personalizados. Observe que há uma anotação alternativa (@ApiTransformer) que é preferível. Este atributo é substituído por @ApiTransformer. transformers = {BazTransformer.class}
version Especifica a versão do endpoint. Se não fornecida, o padrão v1 será usado. version = "v2"

Exemplo de anotação @Api

Essa anotação é colocada antes da definição de classe:

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

IDs do cliente e públicos-alvo

Para a autenticação OAuth2, um token OAuth2 é emitido para um ID do cliente específico. Isso significa que é possível usar o ID do cliente para restringir o acesso às APIs. Ao registrar um aplicativo para Android no Console do Google Cloud, você cria um ID do cliente para ele. O ID do cliente é o que solicita um token OAuth2 do Google para fins de autenticação. Quando a API de back-end é protegida por autenticação, um token de acesso do OAuth2 é enviado e aberto pelo Endpoints, o ID do cliente é extraído do token e, em seguida, comparado com a lista de IDs do cliente do back-end declarados aceitáveis (a lista clientIds).

Se você quiser que a API do Endpoints autentique os autores das chamadas, forneça uma lista de clientIds com permissão para solicitar tokens. É necessário que essa lista tenha todos os IDs do cliente que você recebe por meio do Console do Cloud para seus clientes Android ou Web. Isso significa que você precisa saber quais são os clientes no momento da criação da API. Se você especificar uma lista vazia, {}, nenhum cliente poderá acessar os métodos protegidos pela autenticação.

Se você usar o atributo clientIds e quiser testar chamadas autenticadas para a API usando o Google API Explorer, forneça o ID do cliente na lista de clientIds: o valor a ser usado é com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID.

Sobre públicos-alvo

A lista clientIds protege a API de back-end contra clientes não autorizados. No entanto, é necessário mais segurança para proteger os clientes, para que o token de autenticação funcione somente para a API de back-end pretendida. Para clientes Android, esse mecanismo é o atributo audiences, no qual você especifica o ID do cliente da API de back-end.

Quando você cria um projeto do Console do Cloud, um ID do cliente padrão é gerado e nomeado automaticamente para uso pelo projeto. Ao carregar a API de back-end no App Engine, ele usa esse ID do cliente. Este é o ID do cliente Web mencionado na autenticação da API.

@ApiMethodanotações com escopo do método

A anotação @ApiMethod é usada para fornecer uma configuração de API diferente dos padrões definidos pelas anotações @Api ou @ApiClass. Isso é opcional: todos os métodos públicos, não estáticos e não interligadores em uma classe com uma anotação @Api ficam expostos na API, tenham anotações @ApiMethod ou não.

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

Importações obrigatórias

Para usar esse recurso, são necessárias as 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 de @ApiMethod Descrição Exemplo
apiKeyRequired Opcional. Usado para restringir o acesso a solicitações que fornecem uma chave de API. apiKeyRequired = AnnotationBoolean.TRUE
audiences Forneça-o se quiser modificar a configuração em @API. Para mais informações, consulte IDs do cliente e públicos-alvo. audiences = {"1-web-apps.apps.googleusercontent.com", "2-web-apps.apps.googleusercontent.com"}
authenticators Obrigatório se a API autentica usando Firebase, Auth0 ou contas de serviço e se você não tiver definido esse atributo no nível da API. Este atributo não é obrigatório se a API autentica usando tokens de ID do Google. Defina-o como {EspAuthenticator.class} ou crie seu próprio autenticador personalizado, conforme descrito no Autenticador de interface authenticators = {EspAuthenticator.class}
clientIds Lista de IDs de clientes que solicitam tokens. Obrigatório se a API usa autenticação. clientIds = {"1-web-apps.apps.googleusercontent.com", "2-android-apps.apps.googleusercontent.com"}
httpMethod O método HTTP a ser usado. Se você não defini-lo, será escolhido um padrão com base no nome do método. httpMethod = HttpMethod.GET
issuerAudiences Forneça-o se quiser modificar 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 cota. Atribua a anotação @ApiMetricCost a metricCosts. Também é preciso especificar o atributo limitDefinitions para definir a cota na anotação @Api. A anotação @ApiMetricCost usa os seguintes atributos:
  • name: um nome que você especificou na anotação ApiLimitMetric.
  • custo: um número inteiro que especifica o custo de cada solicitação. O custo permite que os métodos consumam taxas diferentes da mesma cota. Por exemplo, se uma cota tiver um limite de 1.000 e um custo de 1, o aplicativo que faz a chamada pode fazer 1.000 solicitações por minuto antes de ultrapassar o limite. Com um custo de 2 para a mesma cota, um aplicativo que faz a chamada pode fazer apenas 500 solicitações por minuto antes de ultrapassar o limite.
metricCosts = { @ApiMetricCost(name = read-requests", cost = 1) }
name O nome desse método na biblioteca de cliente gerada. Ele é prefixado automaticamente com o nome da API para criar um nome exclusivo para o método. O valor name:
  • precisa começar com caractere minúsculo;
  • precisa corresponder à expressão regular [a-z]+[A-Za-z0-9]*
Se você não especificar name, o padrão myapi será usado.
name = "foosBall.list"
path O caminho de URI usado para acessar esse método. Se você não o definir, será usado um caminho padrão com base no nome do método Java. Se você planeja adicionar o gerenciamento de API, não inclua uma barra no final do caminho. path = "foos"
scopes Especifique um ou mais escopos do OAuth 2.0, sendo um deles obrigatório para chamar esse método. Se você definir scopes para um método, ele modificará a configuração na anotação @Api. Caso mais de um escopo seja definido, observe que a verificação de escopo será aprovada se o token for criado para qualquer um dos escopos especificados. Para exigir vários escopos, especifique um único String com um espaço entre cada escopo. scopes = {"ss0", "ss1 and_ss2"}

Exemplo de anotação @ApiMethod

Essa anotação é colocada antes da definição de método em uma 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 precisam 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 que não sejam entidade transmitidos aos métodos no lado do servidor. Essa anotação indica o nome do parâmetro na solicitação que é injetada aqui. Um parâmetro que não é anotado com @Named é injetado com o objeto de solicitação inteiro.

Importações obrigatórias

Para usar esse recurso, são necessárias as seguintes importações:

import javax.inject.Named;

Este exemplo mostra o uso 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;
}

em que @Named especifica que somente o parâmetro id é injetado na solicitação.

@ApiLimitMetric

Nesta seção, você vê descrições das anotações necessárias para definir as cotas da sua API. Consulte Como configurar cotas para saber sobre todas as etapas necessárias para configurar uma cota.

Atribua a anotação @ApiLimitMetric ao atributo limitDefinitions das anotações com escopo da API. Você também deve adicionar @ApiMetricCost às anotações @ApiMethod para cada método que quiser aplicar uma cota.

Importações obrigatórias

Para usar esse recurso, é necessária a seguinte importação:

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

Atributos

Atributos do @ApiLimitMetric

Descrição
name O nome da cota. Normalmente, é o tipo de solicitação, como "solicitações de leitura" ou "solicitações de gravação", que identifica exclusivamente a cota.
displayName O texto exibido para identificar a cota na guia Cotas em Endpoints > Serviços no Console do Cloud. Esse texto também é exibido para os consumidores da API na página Cotas em "IAM e administrador" e em "API e serviços". O nome de exibição precisa ter no máximo 40 caracteres.
Para facilitar a leitura, o texto "por minuto por projeto" é anexado automaticamente ao nome de exibição nas páginas Cotas.
Para manter a consistência com os nomes de exibição dos serviços do Google listados nas páginas Cotas que aparecem para os consumidores da API, temos as seguintes recomendações para o nome de exibição:
  • Use "Solicitações" quando tiver apenas uma métrica.
  • Quando você tem várias métricas, cada uma deve descrever o tipo de solicitação e conter a palavra "solicitações", por exemplo, "Solicitações de leitura" ou "Solicitações de gravação".
  • Use "unidades de cota" em vez de "solicitações" quando qualquer um dos custos para essa cota for maior que 1.
limit Um valor inteiro que é o número máximo de solicitações por minuto por projeto do consumidor para a cota.

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 namespace especificado, em vez de um padrão construído durante a geração da biblioteca de cliente.

Por padrão, se você não usar essa anotação, o namespace usado será o contrário de your-project-id.appspot.com. Ou seja, o caminho do pacote é com.appspot.your-project-id.yourApi.

Altere o namespace padrão fornecendo a anotação @ApiNamespace dentro de @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 ao domínio da sua empresa e ownerName ao nome da sua empresa, por exemplo, your-company.com. O reverso de ownerDomain é usado para o caminho do pacote: com.your-company.yourApi.

Opcionalmente, você pode usar o atributo packagePath para fornecer mais escopos. Por exemplo, definindo packagePath a cloud, o caminho do pacote usado na biblioteca de cliente é com.your-company.cloud.yourApi. É possível adicionar mais valores ao caminho do pacote fornecendo o delimitador /: packagePath="cloud/platform".

@Nullable

Essa anotação indica que um parâmetro de um método é opcional e, portanto, um parâmetro de consulta. @Nullable é usado apenas com parâmetros @Named.

@ApiClass

Em uma API multiclasse, é possível usar @ApiClass para especificar propriedades diferentes para uma determinada classe, modificando as propriedades equivalentes na configuração de @Api. Consulte Como usar @ApiClass em propriedades que podem diferir entre classes para uma descrição completa dessa anotação.

@ApiReference

Em uma API multiclasse, é possível usar @ApiReference para fornecer um método alternativo de herança de anotações. Consulte Como usar a herança de @ApiReference para uma descrição completa dessa anotação.

@ApiResourceProperty

@ApiResourceProperty fornece controle sobre como as propriedades de recursos são expostas na API. É possível usá-lo em um getter ou setter de uma propriedade para omitir a propriedade de um recurso da API. Também é possível usá-lo no próprio campo, se o campo for privado, para expô-lo na API. Também é possível usar essa anotação para alterar o nome de uma propriedade em um recurso da API.

Importações obrigatórias

Para usar esse recurso, são necessárias as seguintes importações:

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

Atributos

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

Classe de amostra com @ApiResourceProperty

O snippet a seguir mostra uma classe com getters de propriedade 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 snippet de código anterior, @ApiResourceProperty é aplicada ao getter getBin da propriedade bin, com a configuração de atributo ignored informando ao Endpoints Frameworks para omitir essa propriedade no recurso da API.

@ApiResourceProperty também é aplicada ao campo particular visible, que não tem nenhum getter ou setter. Usar essa anotação expõe esse campo como uma propriedade no recurso da API.

No mesmo snippet, @ApiResourceProperty também é aplicada a um getter diferente, getFoobar, que retorna o valor da propriedade foobar. Nessa anotação, o atributo name diz ao Endpoints Frameworks para alterar o nome da propriedade no recurso da API. O valor da propriedade, em si, fica inalterado.

No snippet de exemplo anterior, a representação JSON de um objeto Resp é semelhante a esta:

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

@ApiTransformer

A anotação @ApiTransformer personaliza como um tipo é exposto no Endpoints por meio da transformação de e para outro tipo. O transformador especificado deve ser uma implementação de com.google.api.server.spi.config.Transformer.

Usar a anotação @ApiTransformer em uma classe é o modo recomendado de especificar um transformador. No entanto, você pode especificar seu transformador personalizado no atributo transformer da anotação @Api.

Importações obrigatórias

Para usar esse recurso, é necessária a seguinte importação:

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

Exemplo de classe com @ApiTransformer

O snippet a seguir 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 classe é transformada pela classe BarTransformer.

Exemplo de classe de transformador do Endpoints

O snippet a seguir mostra um exemplo de classe de transformação chamada BarTransformer. Este é o transformador mencionado por @ApiTransformer no snippet 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 haja um objeto com uma propriedade bar do tipo Bar, sem o transformador anterior, o objeto é representado como:

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

Com o transformador, o objeto é representado como:

{"bar": "1,2"}