Annotations et syntaxe Cloud Endpoints Frameworks

Les annotations Endpoints Frameworks décrivent la configuration, les méthodes, les paramètres et d'autres informations essentielles de l'API qui définissent les propriétés et le comportement du point de terminaison.

Consultez la section Écrire et annoter le code pour plus d'informations sur l'ajout d'annotations à l'aide d'un projet Maven. Les artefacts Maven App Engine Cloud Endpoints sont fournis pour créer et construire une API backend, ainsi que pour générer une bibliothèque cliente à partir de celle-ci.

L'annotation qui spécifie la configuration et le comportement de l'ensemble de l'API (affectant toutes les classes exposées dans l'API et toutes leurs méthodes exposées) est @Api. Toutes les méthodes publiques, non statiques et sans pont d'une classe annotée avec @Api sont exposées dans l'API publique.

Si vous avez besoin d'une configuration d'API spéciale pour une méthode particulière, vous pouvez éventuellement utiliser @ApiMethod pour définir la configuration méthode par méthode. Vous pouvez configurer ces annotations en définissant divers attributs, comme indiqué dans les tableaux ci-dessous.

@Api : annotations appliquées au niveau de l'API

L'annotation @Api configure l'intégralité de l'API et s'applique à toutes les méthodes publiques d'une classe, à moins qu'elle ne soit remplacée par @ApiMethod.

Pour remplacer une annotation @Api donnée pour une classe spécifique au sein d'une API, consultez @ApiClass et @ApiReference.

Importations requises

Pour utiliser cette fonctionnalité, vous avez besoin de l'importation suivante :

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

Attributs

Attributs @Api Description Exemple
audiences Obligatoire si votre API requiert une authentification et si vous prenez en charge les clients Android. Pour plus d'informations, consultez la section Identifiants client et Audiences. audiences = {"1-web-apps.apps.googleusercontent.com", "2-web-apps.apps.googleusercontent.com"}
apiKeyRequired Facultatif. Utilisé pour limiter l'accès aux requêtes fournissant une clé Api. apiKeyRequired = AnnotationBoolean.TRUE
authenticators Obligatoire si votre API s'authentifie à l'aide de Firebase, Auth0 ou de comptes de service. Cet attribut n'est pas nécessaire si votre API s'authentifie à l'aide de jetons Google ID. Vous pouvez définir cela au niveau de l'API ou au niveau de la méthode individuelle. Définissez-le sur {EspAuthenticator.class} ou écrivez votre propre authentificateur personnalisé, comme décrit sur la page Interface Authenticator. authenticators = {EspAuthenticator.class}
backendRoot Obsolète. Pour diffuser votre API depuis un autre chemin d'accès, dans votre fichier web.xml, modifiez l'élément url-pattern de la section EndpointsServlet. <url-pattern>/example-api/*</url-pattern>
canonicalName Utilisé pour spécifier un nom différent ou plus lisible pour l'API dans la bibliothèque cliente. Ce nom est utilisé pour générer ceux de la bibliothèque cliente. L'API backend continue d'utiliser la valeur spécifiée dans la propriété name.

Par exemple, si la propriété name de votre API est définie sur dfaanalytics, vous pouvez utiliser cette propriété pour spécifier le nom canonique de DFA Group Analytics. Les classes de client générées contiennent alors le nom DfaGroupAnalytics.

Vous devez inclure les espaces appropriés entre les noms. Ceux-ci seront complétés par le camel case ou les traits de soulignement appropriés.
canonicalName = "DFA Analytics:"n
clientIds Requis si votre API utilise l'authentification. Liste des ID client autorisés à demander des jetons. Pour plus d'informations, consultez la section ID client et Audiences. clientIds = {"1-web-apps.apps.googleusercontent.com", "2-android-apps.apps.googleusercontent.com"}
defaultVersion Spécifie si une version par défaut est utilisée lorsqu'aucune version n'est fournie dans l'attribut version. defaultVersion = AnnotationBoolean.TRUE
description Brève description de l'API. Ce nom est exposé dans le service de découverte pour décrire votre API et peut éventuellement être utilisé pour générer de la documentation. description = "Sample API for a simple game"
documentationLink URL où les utilisateurs peuvent trouver de la documentation sur cette version de l'API. Elle est utilisée pour le lien "En savoir plus", situé en haut de la page de l'explorateur d'API, pour permettre aux utilisateurs de se familiariser avec votre service. documentationLink = "http://link_to/docs"
issuers Configurations d'émetteur JWT personnalisées. issuers = { @ApiIssuer(name = "auth0", issuer = "https://test.auth0.com/authorize", jwksUri = "https://test.auth0.com/.well-known/jwks.json") }
issuerAudiences Audiences pour les émetteurs individuels. issuerAudiences = { @ApiIssuerAudience(name = "auth0", audiences = {"aud-1.auth0.com", "aud-2.auth0.com"}) }
limitDefinitions Facultatif. Utilisé pour définir des quotas pour votre API. Consultez @ApiLimitMetric. limitDefinitions = { @ApiLimitMetric(name = "read-requests", displayName = "Read requests", limit = 1000)}
name Nom de l'API, utilisé comme préfixe pour toutes les méthodes et tous les chemins d'accès de l'API. La valeur name :
  • doit commencer par une minuscule ;
  • doit correspondre à l'expression régulière [a-z]+[A-Za-z0-9]*.
Si vous ne spécifiez pas name, la valeur par défaut myapi est utilisée.
name = "foosBall"
namespace Configure l'espace de noms pour les clients générés. Consultez @ApiNamespace. namespace=@ApiNamespace(ownerDomain="your-company.com", ownerName="YourCo", packagePath="cloud/platform")
root Obsolète. Pour diffuser votre API depuis un autre chemin d'accès, dans votre fichier web.xml, modifiez l'élément url-pattern de la section EndpointsServlet. <url-pattern>/example-api/*</url-pattern>
scopes S'il n'est pas renseigné, la valeur par défaut est le champ d'application de l'adresse e-mail (https://www.googleapis.com/auth/userinfo.email), obligatoire pour OAuth. Vous pouvez le remplacer pour spécifier davantage de champs d'application OAuth 2.0 si vous le souhaitez. Toutefois, si vous définissez plusieurs champs d'application, notez que la vérification du champ d'application est validée si le jeton est attribué à n'importe lequel des champs d'application spécifiés. Pour exiger plusieurs champs d'application, une seule chaîne (String) doit être spécifiée avec une espace entre chaque champ d'application. Pour remplacer les champs d'application spécifiés ici pour une méthode d'API particulière, spécifiez des champs d'application différents dans l'annotation @ApiMethod. scopes = {"ss0", "ss1 and_ss2"}
title Texte affiché dans l'explorateur d'API comme titre de votre API et exposé dans les services de découverte et d'annuaire. title = "My Backend API"
transformers Spécifie une liste de transformateurs personnalisés. Notez qu'il existe une annotation alternative privilégiée (@ApiTransformer). Cet attribut est remplacé par @ApiTransformer. transformers = {BazTransformer.class}
version Spécifie votre version de Endpoints. Si vous ne l'indiquez pas, la valeur par défaut v1 est utilisée. version = "v2"

Exemple d'annotation @Api

Cette annotation est placée au-dessus de la définition de classe :

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

ID client et Audiences

Pour l'authentification OAuth2, un jeton OAuth2 est émis pour un ID client spécifique, ce qui signifie que vous pouvez utiliser l'ID client pour restreindre l'accès à vos API. Lorsque vous enregistrez une application Android dans la console Google Cloud, vous créez un ID client pour cette application. Cet ID client est celui qui demande un jeton OAuth2 à Google à des fins d'authentification. Lorsque l'API backend est protégée par authentification, un jeton d'accès OAuth2 est envoyé et ouvert par Endpoints. L'ID client est extrait du jeton, puis comparé à la liste d'ID client acceptables du backend (liste clientIds).

Si vous souhaitez que votre API Endpoints authentifie les appelants, vous devez fournir une liste de clientIds autorisés à demander des jetons. Cette liste doit contenir tous les ID client obtenus via la console Google Cloud pour vos clients Web ou Android. Cela signifie que les clients doivent être connus au moment de la création de l'API. Si vous spécifiez une liste vide, {}, aucun client ne peut accéder aux méthodes protégées par authentification.

Si vous utilisez l'attribut clientIds et que vous souhaitez tester les appels authentifiés à votre API à l'aide de l'explorateur d'API Google, vous devez indiquer son ID client dans la liste de clientIds : la valeur à utiliser est com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID.

À propos des audiences

La liste de clientIds protège l'API backend des clients non autorisés. Toutefois, une protection supplémentaire est nécessaire pour protéger les clients, afin que leur jeton d'authentification ne fonctionne que pour l'API backend prévue. Pour les clients Android, ce mécanisme correspond à l'attribut audiences, dans lequel vous spécifiez l'ID client de l'API backend.

Notez que lorsque vous créez un projet dans la console Google Cloud, un ID client par défaut est automatiquement créé et nommé pour être utilisé par le projet. Lorsque vous importez l'API backend dans App Engine, elle utilise cet ID client. Il s'agit de l'ID de client Web mentionné dans l'authentification de l'API.

@ApiMethod : annotations appliquées au niveau de la méthode

L'annotation @ApiMethod est utilisée pour fournir une configuration d'API différente de celle proposée par défaut par les annotations @Api ou @ApiClass. Notez que cela est facultatif : toutes les méthodes publiques, non statiques et sans pont dans une classe comportant une annotation @Api sont exposées dans l'API, qu'elles aient une annotation @ApiMethod ou non.

Les attributs dans cette annotation vous permettent de configurer les détails d'une seule méthode d'API. Si le même attribut est spécifié dans @Api et @ApiMethod, @ApiMethod prend le dessus.

Importations requises

Pour utiliser cette fonctionnalité, vous avez besoin des importations suivantes :

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;

Attributs

Attributs @ApiMethod Description Exemple
apiKeyRequired Facultatif. Utilisé pour limiter l'accès aux requêtes fournissant une clé API. apiKeyRequired = AnnotationBoolean.TRUE
audiences Indiquez cet attribut si vous souhaitez écraser la configuration dans @API. Pour plus d'informations, consultez la section ID client et Audiences. audiences = {"1-web-apps.apps.googleusercontent.com", "2-web-apps.apps.googleusercontent.com"}
authenticators Obligatoire si votre API s'authentifie à l'aide de Firebase, Auth0 ou de comptes de service, et que vous n'avez pas défini cet attribut au niveau de l'API. Cet attribut n'est pas nécessaire si votre API s'authentifie à l'aide de jetons d'ID Google. Définissez-le sur {EspAuthenticator.class} ou écrivez votre propre authentificateur personnalisé, comme décrit sur la page Interface Authenticator. authenticators = {EspAuthenticator.class}
clientIds Liste des ID client autorisés à demander des jetons. Obligatoire si votre API utilise l'authentification. clientIds = {"1-web-apps.apps.googleusercontent.com", "2-android-apps.apps.googleusercontent.com"}
httpMethod Méthode HTTP à utiliser. Si vous ne la définissez pas, une valeur par défaut est choisie en fonction du nom de la méthode. httpMethod = HttpMethod.GET
issuerAudiences Indiquez cet attribut si vous souhaitez écraser la configuration dans @Api. issuerAudiences = { @ApiIssuerAudience(name = "auth0", audiences = {"aud-1.auth0.com", "aud-2.auth0.com"}) }
metricCosts Facultatif. Indique que la méthode a une limite de quota. Vous attribuez l'annotation @ApiMetricCost à metricCosts. Vous devez également spécifier l'attribut limitDefinitions pour définir le quota dans l'annotation @Api. L'annotation @ApiMetricCost utilise les attributs suivants :
  • name : le nom que vous avez spécifié dans l'annotation ApiLimitMetric.
  • cost : entier indiquant le coût de chaque requête. Le coût permet aux méthodes de consommer à des taux différents sur un même quota. Par exemple, si un quota a une limite de 1 000 et un coût de 1, l'application appelante peut effectuer 1 000 requêtes par minute avant de dépasser la limite. Avec un coût de 2 pour le même quota, une application appelante ne peut effectuer que 500 demandes par minute avant de dépasser la limite.
metricCosts = { @ApiMetricCost(name = read-requests", cost = 1) }
name Nom de cette méthode dans la bibliothèque cliente générée. Celui-ci est automatiquement préfixé avec votre nom d'API pour créer un nom unique pour la méthode. La valeur name :
  • doit commencer par une minuscule ;
  • doit correspondre à l'expression régulière [a-z]+[A-Za-z0-9]*.
Si vous ne spécifiez pas name, la valeur par défaut myapi est utilisée.
name = "foosBall.list"
path Chemin d'URI à utiliser pour accéder à cette méthode. Si vous ne le configurez pas, un chemin par défaut est utilisé en fonction du nom de la méthode Java. Si vous envisagez d'ajouter la gestion de l'API, n'ajoutez pas de barre oblique finale au chemin. path = "foos"
scopes Spécifiez un ou plusieurs champs d'application OAuth 2.0, dont l'un est obligatoire pour appeler cette méthode. Si vous définissez l'attribut scopes pour une méthode, il remplace le paramétrage de l'annotation @Api. Si vous définissez plusieurs champs d'application, notez que la vérification du champ d'application sera validée si le jeton est attribué à n'importe lequel des champs d'application spécifiés. Pour exiger plusieurs champs d'application, une seule chaîne (String) doit être spécifiée avec une espace entre chaque champ d'application. scopes = {"ss0", "ss1 and_ss2"}

Exemple d'annotation @ApiMethod

Cette annotation se place au-dessus de la définition de la méthode dans une 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;
}

Les méthodes qui utilisent une entité comme paramètre doivent utiliser HttpMethod.POST (pour les opérations d'insertion) ou HttpMethod.PUT (pour les opérations de mise à jour) :

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

@Named

L'annotation @Named est obligatoire pour tous les paramètres transmis aux méthodes côté serveur qui ne sont pas de type entité. Cette annotation indique le nom du paramètre dans la requête injectée ici. Un paramètre qui n'est pas annoté avec @Named est injecté avec l'intégralité de l'objet de la requête.

Importations requises

Pour utiliser cette fonctionnalité, vous avez besoin des importations suivantes :

import javax.inject.Named;

Cet exemple présente l'utilisation 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;
}

@Named indique que seul le paramètre id est injecté dans la requête.

@ApiLimitMetric

Cette section décrit les annotations requises pour définir des quotas pour votre API. Consultez la page Configurer des quotas pour connaître toutes les étapes nécessaires à la configuration d'un quota.

Vous attribuez l'annotation @ApiLimitMetric à l'attribut limitDefinitions des annotations appliquées au niveau de l'API. Vous devez également ajouter @ApiMetricCost aux annotations @ApiMethod pour chaque méthode à laquelle vous souhaitez appliquer un quota.

Importations requises

Pour utiliser cette fonctionnalité, vous avez besoin de l'importation suivante :

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

Attributs

Attributs @ApiLimitMetric

Description
name Nom du quota. En règle générale, il s'agit du type de requête (par exemple, "Read-requests" ou "Write-requests") qui identifie de manière unique le quota.
displayName Texte affiché pour identifier le quota dans l'onglet Quotas de la page Endpoints > Services de la console Google Cloud. Ce texte est également affiché pour les utilisateurs de votre API sur la page Quotas dans "IAM et administration" et dans "API et services". Le nom d'affichage doit comporter 40 caractères au maximum.
Par souci de lisibilité, le texte "par minute par projet" est automatiquement ajouté au nom à afficher sur les pages Quotas.
Pour maintenir la cohérence avec les noms à afficher des services Google répertoriés sur les pages Quotas que les consommateurs de votre API voient, nous vous recommandons ce qui suit pour le nom à afficher :
  • Utilisez "Requêtes" lorsque vous n'avez qu'une seule métrique.
  • Lorsque vous disposez de plusieurs métriques, chacune doit décrire le type de requête et contenir le mot "Requests" (par exemple "Read requests" ou "Write requests").
  • Utilisez "quota units" au lieu de "requests" lorsque l'un des coûts de ce quota est supérieur à 1.
limit Valeur entière représentant le nombre maximal de requêtes par minute par projet client pour le quota.

Exemple

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

@ApiNamespace

L'annotation @ApiNamespace fait que les bibliothèques clientes générées ont l'espace de noms que vous spécifiez, plutôt qu'une valeur par défaut créée lors de la génération de la bibliothèque cliente.

Par défaut, si vous n'utilisez pas cette annotation, l'espace de noms utilisé est l'inverse de your-project-id.appspot.com. Autrement dit, le chemin du package est com.appspot.your-project-id.yourApi.

Vous pouvez modifier l'espace de noms par défaut en indiquant l'annotation @ApiNamespace dans l'annotation @Api :

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

Définissez l'attribut ownerDomain sur votre propre domaine d'entreprise et ownerName sur le nom de votre entreprise, par exemple your-company.com. L'inverse de ownerDomain est utilisé pour le chemin du package : com.your-company.yourApi.

Vous pouvez éventuellement utiliser l'attribut packagePath pour fournir un champ d'application supplémentaire. Par exemple, en définissant packagePath sur cloud, le chemin du package utilisé dans la bibliothèque cliente est com.your-company.cloud.yourApi. Vous pouvez ajouter d'autres valeurs au chemin du package en indiquant le délimiteur / : packagePath="cloud/platform".

@Nullable

Cette annotation indique qu'un paramètre de méthode est facultatif (et donc un paramètre de requête). @Nullable ne peut être utilisé qu'avec les paramètres @Named.

@ApiClass

Dans une API multiclasse, vous pouvez utiliser @ApiClass pour spécifier différentes propriétés pour une classe donnée, ignorant ainsi les propriétés équivalentes dans la configuration @Api. Consultez la section Utiliser @ApiClass pour connaître les propriétés pouvant différer entre les classes afin d'obtenir une description complète de cette annotation.

@ApiReference

Dans une API multiclasse, vous pouvez utiliser @ApiReference pour fournir une autre méthode d'héritage d'annotation. Pour obtenir une description complète de cette annotation, consultez la section Utiliser l'héritage @ApiReference.

@ApiResourceProperty

@ApiResourceProperty contrôle la manière dont les propriétés de ressources sont exposées dans l'API. Vous pouvez l'utiliser sur un "getter" ou un "setter" de propriété pour omettre la propriété dans une ressource d'API. Vous pouvez également l'utiliser dans le champ lui-même, si celui-ci est privé, pour l'exposer dans l'API. Mais vous pouvez aussi utiliser cette annotation pour modifier le nom d'une propriété dans une ressource d'API.

Importations requises

Pour utiliser cette fonctionnalité, vous avez besoin des importations suivantes :

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

Attributs

Attributs @ApiResourceProperty Description Exemple
ignored S'il est défini sur AnnotationBoolean.TRUE, il omet la propriété. S'il n'est pas spécifié ou s'il est défini sur AnnotationBoolean.FALSE, la propriété n'est pas omise. @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
name S'il est fourni, il spécifie le nom de la propriété à exposer dans l'API. @ApiResourceProperty(name = "baz")

Exemple de classe avec @ApiResourceProperty

L'extrait suivant montre une classe avec des "getters" de propriétés annotés avec @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();
}

Dans l'extrait de code ci-dessus, @ApiResourceProperty est appliqué au "getter" getBin pour la propriété bin, le paramètre d'attribut ignored indiquant à Endpoints Frameworks d'omettre cette propriété dans la ressource d'API.

@ApiResourceProperty est également appliqué au champ privé visible, qui n'a ni "getter", ni "setter". L'utilisation de cette annotation expose ce champ en tant que propriété dans la ressource d'API.

Dans le même extrait, @ApiResourceProperty est également appliqué à un "getter" différent, getFoobar, qui renvoie une valeur de propriété pour la propriété foobar. L'attribut name de cette annotation indique à Endpoints Frameworks de modifier le nom de la propriété dans la ressource d'API. La valeur de la propriété elle-même reste inchangée.

Dans l'exemple ci-dessus, la représentation JSON d'un objet Resp ressemble à ceci :

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

@ApiTransformer

L'annotation @ApiTransformer personnalise la manière dont un type est exposé dans Endpoints par le biais d'une transformation vers et à partir d'un autre type. (Le transformateur spécifié doit être une mise en œuvre de com.google.api.server.spi.config.Transformer.)

L'utilisation de l'annotation @ApiTransformer sur une classe est la méthode privilégiée pour spécifier un transformateur. Cependant, il est parfois possible de spécifier un transformateur personnalisé dans l'attribut transformer de l'annotation @Api.

Importations requises

Pour utiliser cette fonctionnalité, vous avez besoin de l'importation suivante :

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

Exemple de classe avec @ApiTransformer

L'extrait suivant présente une classe annotée avec @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;
  }
}

Cette classe est transformée par la classe BarTransformer.

Exemple de classe de transformateur Endpoints

L'extrait suivant présente un exemple de classe de transformateur nommé BarTransformer. Il s'agit du transformateur référencé par @ApiTransformer dans l'extrait précédent :

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]));
  }
}

En supposant qu'il existe un objet comportant une propriété bar de type Bar, sans le transformateur ci-dessus, l'objet est représenté comme suit :

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

Avec le transformateur, l'objet est représenté comme suit :

{"bar": "1,2"}