Documentation de référence de la syntaxe du langage d'expression commun pour Data Connect

Ce guide de référence couvre la syntaxe CEL (Common Expression Language) pertinente pour la création d'expressions pour les directives @auth(expr:) et @check(expr:).

Vous trouverez des informations de référence complètes sur CEL dans la spécification CEL.

Variables de test transmises dans les requêtes et les mutations

La syntaxe @auth(expr) vous permet d'accéder aux variables à partir de requêtes et de mutations, et de les tester.

Par exemple, vous pouvez inclure une variable d'opération, telle que $status, à l'aide de vars.status.

mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")

Données disponibles pour les expressions: request, response, this

Vous utilisez les données pour:

  • Évaluation avec des expressions CEL dans les directives @auth(expr:) et @check(expr:)
  • Affectation à l'aide d'expressions de serveur, <field>_expr.

Les expressions CEL @auth(expr:) et @check(expr:) peuvent évaluer les éléments suivants:

  • request.operationName
  • vars (alias de request.variables)
  • auth (alias de request.auth)

Dans les mutations, vous pouvez accéder aux contenus suivants et les attribuer:

  • response (pour vérifier les résultats partiels dans une logique en plusieurs étapes)

De plus, les expressions @check(expr:) peuvent évaluer:

  • this (valeur du champ actuel)
  • response (pour vérifier les résultats partiels dans une logique en plusieurs étapes)

Liaison request.operationName

La liaison request.operarationName stocke le type d'opération, qu'il s'agisse d'une requête ou d'une mutation.

L'association vars (request.vars)

La liaison vars permet à vos expressions d'accéder à toutes les variables transmises dans votre requête ou votre mutation.

Vous pouvez utiliser vars.<variablename> dans une expression comme alias du request.variables.<variablename> qualifié complet:

# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")

La liaison auth (request.auth)

Authentication identifie les utilisateurs qui demandent l'accès à vos données et fournit ces informations en tant que liaison sur laquelle vous pouvez vous appuyer dans vos expressions.

Dans vos filtres et expressions, vous pouvez utiliser auth comme alias pour request.auth.

La liaison d'authentification contient les informations suivantes:

  • uid: ID utilisateur unique attribué à l'utilisateur à l'origine de la requête.
  • token: carte des valeurs collectées par Authentication.

Pour en savoir plus sur le contenu de auth.token, consultez la section Données dans les jetons d'authentification.

Liaison response

La liaison response contient les données assemblées par le serveur en réponse à une requête ou une mutation lors de leur assemblage.

Au fur et à mesure de l'opération, à mesure que chaque étape est terminée, response contient les données de réponse des étapes terminées avec succès.

La liaison response est structurée en fonction de la forme de l'opération associée, y compris (plusieurs) champs imbriqués et (le cas échéant) des requêtes intégrées.

Notez que lorsque vous accédez aux données de réponse de requête intégrée, les champs peuvent contenir n'importe quel type de données, en fonction des données demandées dans la requête intégrée. Lorsque vous accédez aux données renvoyées par des champs de mutation tels que _insert et _delete, ils peuvent contenir des clés UUID, un nombre de suppressions et des valeurs nulles (voir la référence sur les mutations).

Exemple :

  • Dans une mutation contenant une requête intégrée, la liaison response contient des données de recherche à response.query.<fieldName>.<fieldName>...., dans ce cas, response.query.todoList et response.query.todoList.priority.
mutation CheckTodoPriority(
  $uniqueListName: String!
) {
  # This query is identified as `response.query`
  query @check(expr: "response.query.todoList.priority == 'high'", message: "This list is not for high priority items!") {
    # This field is identified as `response.query.todoList`
    todoList(where: { name: $uniqueListName }) {
      # This field is identified as `response.query.todoList.priority`
      priority
    }
  }
}
  • Dans une mutation en plusieurs étapes, par exemple avec plusieurs champs _insert, la liaison response contient des données partielles à response.<fieldName>.<fieldName>...., dans ce cas response.todoList_insert.id.
mutation CreateTodoListWithFirstItem(
  $listName: String!,
  $itemContent: String!
) @transaction {
  # Step 1
  todoList_insert(data: {
    id_expr: "uuidV4()",
    name: $listName,
  })
  # Step 2:
  todo_insert(data: {
    listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
    content: $itemContent,
  })
}

Liaison this

La liaison this renvoie le champ auquel la directive @check est associée. Dans un cas de base, vous pouvez évaluer les résultats de requête à valeur unique.

mutation UpdateMovieTitle (
  $movieId: UUID!,
  $newTitle: String!)
  @auth(level: USER)
  @transaction {
  # Step 1: Query and check
  query @redact {
    moviePermission( # Look up a join table called MoviePermission with a compound key.
      key: {movieId: $movieId, userId_expr: "auth.uid"}
    ) {
      # Check if the user has the editor role for the movie. `this` is the string value of `role`.
      # If the parent moviePermission is null, the @check will also fail automatically.
      role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Si le champ renvoyé apparaît plusieurs fois, car un ancêtre est une liste, chaque occurrence est testée avec this lié à chaque valeur.

Pour un chemin donné, si un ancêtre est null ou [], le champ ne sera pas atteint et l'évaluation CEL sera ignorée pour ce chemin. En d'autres termes, l'évaluation n'a lieu que lorsque this est null ou non null, mais jamais undefined.

Lorsque le champ lui-même est une liste ou un objet, this suit la même structure (y compris tous les descendants sélectionnés en cas d'objets), comme illustré dans l'exemple suivant.

mutation UpdateMovieTitle2($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query {
    moviePermissions( # Now we query for a list of all matching MoviePermissions.
      where: {movieId: {eq: $movieId}, userId: {eq_expr: "auth.uid"}}
    # This time we execute the @check on the list, so `this` is the list of objects.
    # We can use the `.exists` macro to check if there is at least one matching entry.
    ) @check(expr: "this.exists(p, p.role == 'editor')", message: "You must be an editor of this movie to update title") {
      role
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Syntaxe des expressions complexes

Vous pouvez écrire des expressions plus complexes en les combinant avec les opérateurs && et ||.

mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")

La section suivante décrit tous les opérateurs disponibles.

Opérateurs et priorité des opérateurs

Utilisez le tableau suivant comme référence pour les opérateurs et leur priorité correspondante.

Étant donné des expressions arbitraires a et b, un champ f et un indice i.

Opérateur Description Associativité
a[i] a() a.f Index, appel, accès aux champs de gauche à droite
!a -a Négation unaire de droite à gauche
a/b a%b a*b Opérateurs multiplicatifs de gauche à droite
a+b a-b Opérateurs additifs de gauche à droite
a>b a>=b a<b a<=b Opérateurs relationnels de gauche à droite
a in b Existence dans une liste ou une carte de gauche à droite
type(a) == t Comparaison de types, où t peut être bool, int, float, nombre, chaîne, liste, mappage, code temporel ou durée de gauche à droite
a==b a!=b Opérateurs de comparaison de gauche à droite
a && b Opérateur AND conditionnel de gauche à droite
a || b OR conditionnel de gauche à droite
a ? true_value : false_value Expression ternaire de gauche à droite

Données dans les jetons d'authentification

L'objet auth.token peut contenir les valeurs suivantes:

Champ Description
email Adresse e-mail associée au compte, le cas échéant.
email_verified true si l'utilisateur a confirmé qu'il avait accès à l'adresse email. Certains fournisseurs valident automatiquement les adresses e-mail qu'ils possèdent.
phone_number Numéro de téléphone associé au compte, le cas échéant
name Nom à afficher de l'utilisateur, le cas échéant.
sub UID Firebase de l'utilisateur. Il doit être unique au sein d'un projet.
firebase.identities Dictionnaire de toutes les identités associées au compte de cet utilisateur. Les clés du dictionnaire peuvent être l'une des valeurs suivantes: email, phone, google.com, facebook.com, github.com ou twitter.com. Les valeurs du dictionnaire sont des tableaux d'identifiants uniques pour chaque fournisseur d'identité associé au compte. Par exemple, auth.token.firebase.identities["google.com"][0] contient le premier ID utilisateur Google associé au compte.
firebase.sign_in_provider Fournisseur de connexion utilisé pour obtenir ce jeton. Peut être l'une des chaînes suivantes: custom, password, phone, anonymous, google.com, facebook.com, github.com ou twitter.com.
firebase.tenant ID de locataire associé au compte, le cas échéant. Par exemple : tenant2-m6tyz

Champs supplémentaires dans les jetons d'ID JWT

Vous pouvez également accéder aux champs auth.token suivants:

Revendications de jetons personnalisées
alg Algorithme "RS256"
iss Émetteur Adresse e-mail du compte de service de votre projet
sub Objet Adresse e-mail du compte de service de votre projet
aud Audience "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Date/Heure d'émission Heure actuelle, en secondes depuis l'epoch UNIX
exp Date/Heure d'expiration Durée, en secondes depuis l'époque UNIX, au bout de laquelle le jeton expire. Cette valeur peut correspondre à un maximum de 3 600 secondes après l'heure iat.
Remarque : Cette valeur ne contrôle que l'heure d'expiration du jeton personnalisé lui-même. Cependant, une fois que l'utilisateur est connecté à l'aide de signInWithCustomToken(), il reste connecté à l'appareil jusqu'à ce que sa session soit invalide ou qu'il se déconnecte.
<claims> (facultatif) Revendications personnalisées facultatives à inclure dans le jeton, auxquelles vous pouvez accéder via auth.token (ou request.auth.token) dans les expressions. Par exemple, si vous créez une revendication personnalisée adminClaim, vous pouvez y accéder avec auth.token.adminClaim.