Este guia de referência aborda a sintaxe da Common Expression Language (CEL) relevante para a criação de expressões para as diretivas @auth(expr:), @check(expr:) e @refresh(onMutationExecuted:).
Informações de referência completas para CEL são fornecidas na especificação da CEL.
Variáveis de teste transmitidas em consultas e mutações
A sintaxe @auth(expr) permite acessar e testar variáveis de consultas e mutações.
Por exemplo, é possível incluir uma variável de operação, como $status, usando vars.status.
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
Dados disponíveis para expressões: request, response, this
Você usa dados para:
- Avaliação com expressões CEL nas diretivas
@auth(expr:)e@check(expr:) - Atribuição usando expressões de servidor,
<field>_expr.
As expressões CEL @auth(expr:), @check(expr:), @refresh(onMutationExecuted:) podem avaliar o seguinte:
request.operationNamevars(alias pararequest.variables)auth(alias pararequest.auth)
Em mutações, é possível acessar e atribuir o conteúdo de:
response(para verificar resultados parciais na lógica de várias etapas)
Além disso, as expressões @check(expr:) podem avaliar:
this(o valor do campo atual)response(para verificar resultados parciais na lógica de várias etapas)
E as expressões @refresh(onMutationExecuted:) têm a seguinte vinculação:
mutation.variablesmutation.auth
A vinculação request.operationName
A vinculação request.operarationName armazena o tipo de operação, consulta ou mutação.
A vinculação vars (request.vars)
A vinculação vars permite que suas expressões acessem todas as variáveis transmitidas na consulta ou mutação.
É possível usar vars.<variablename> em uma expressão como um alias para o
totalmente qualificado request.variables.<variablename>:
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
A vinculação auth (request.auth)
Authentication identifica os usuários que solicitam acesso aos seus dados e fornece essas informações como uma vinculação que pode ser criada nas suas expressões.
Nos filtros e expressões, é possível usar auth como um alias para
request.auth.
A vinculação de autenticação contém as seguintes informações:
uid: um ID de usuário exclusivo, atribuído ao usuário solicitante.token: um mapa de valores coletados pelo Authentication.
Para mais detalhes sobre o conteúdo de auth.token, consulte
Dados em tokens de autenticação
A vinculação response
A vinculação response contém os dados que estão sendo montados pelo servidor em resposta a uma consulta ou mutação à medida que esses dados são montados.
À medida que a operação avança, e cada etapa é concluída com sucesso, response contém dados de resposta de etapas concluídas com sucesso.
A vinculação response é estruturada de acordo com a forma da operação associada, incluindo campos aninhados (múltiplos) e consultas incorporadas (se aplicável).
Observe que, ao acessar dados de resposta de consulta incorporada, os campos podem conter
qualquer tipo de dados, dependendo dos dados solicitados na consulta incorporada; ao
acessar dados retornados por campos de mutação, como _inserts e _deletes, eles podem
conter chaves UUID, número de exclusões, nulos (consulte a
referência de mutações).
Exemplo:
- Em uma mutação que contém uma consulta incorporada, a
responsevinculação contém dados de pesquisa emresponse.query.<fieldName>.<fieldName>...., em neste caso,response.query.todoListeresponse.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
}
}
}
- Em uma mutação de várias etapas, por exemplo, com vários campos
_insert, aresponsevinculação contém dados parciais emresponse.<fieldName>.<fieldName>...., nesse caso,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,
})
}
A vinculação this
A vinculação this é avaliada no campo ao qual a diretiva @check está anexada. Em um caso básico, é possível avaliar resultados de consultas de valor único.
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
})
}
Se o campo retornado ocorrer várias vezes porque qualquer ancestral é uma lista, cada ocorrência será testada com this vinculada a cada valor.
Para qualquer caminho, se um ancestral for null ou [], o campo não será acessado e a avaliação da CEL será ignorada para esse caminho. Em outras palavras, a avaliação só ocorre quando this é null ou não null, mas nunca undefined.
Quando o campo em si é uma lista ou um objeto, this segue a mesma estrutura (incluindo todos os descendentes selecionados no caso de objetos), conforme ilustrado no exemplo a seguir.
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
})
}
Sintaxe de expressão complexa
É possível escrever expressões mais complexas combinando com os && e ||
operadores.
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
A seção a seguir descreve todos os operadores disponíveis.
Operadores e precedência do operador
Use a tabela a seguir como referência para os operadores e a precedência correspondente deles.
Expressões arbitrárias fornecidas a e b, um campo f e um índice i.
| Operador | Descrição | Associatividade |
|---|---|---|
a[i] a() a.f |
Índice, chamada, acesso ao campo | da esquerda para a direita |
!a -a |
Negação unária | da direita para a esquerda |
a/b a%b a*b |
Operadores multiplicativos | da esquerda para a direita |
a+b a-b |
Operadores aditivos | da esquerda para a direita |
a>b a>=b a<b a<=b |
Operadores relacionais | da esquerda para a direita |
a in b |
Existência na lista ou no mapa | da esquerda para a direita |
type(a) == t |
Comparação de tipos, em que t pode ser bool, int, float,
number, string, list, map, timestamp ou duration |
da esquerda para a direita |
a==b a!=b |
Operadores de comparação | da esquerda para a direita |
a && b |
Condicional E | da esquerda para a direita |
a || b |
Condicional OU | da esquerda para a direita |
a ? true_value : false_value |
Expressão ternária | da esquerda para a direita |
Dados em tokens de autenticação
O objeto auth.token pode conter os seguintes valores:
| Campo | Descrição |
|---|---|
email |
O endereço de e-mail associado à conta, se essa informação existir. |
email_verified |
true se o usuário tiver verificado que tem acesso ao endereço email. Alguns provedores verificam automaticamente esses endereços de e-mail. |
phone_number |
O número de telefone associado à conta, se essa informação existir. |
name |
O nome de exibição do usuário, se ele tiver sido definido. |
sub |
O UID do Firebase do usuário. Ele é exclusivo em um projeto. |
firebase.identities |
O dicionário de todas as identidades associadas à conta desse usuário. As chaves do dicionário podem ser qualquer uma das seguintes: email, phone, google.com, facebook.com, github.com, twitter.com. Os valores do dicionário são matrizes de identificadores exclusivos de cada provedor de identidade associado à conta. Por exemplo, auth.token.firebase.identities["google.com"][0] contém o primeiro ID de usuário do Google associado à conta. |
firebase.sign_in_provider |
O provedor de entrada usado para receber esse token. Pode ser uma das seguintes strings: custom, password, phone, anonymous, google.com, facebook.com, github.com, twitter.com. |
firebase.tenant |
O ID do locatário associado à conta, se houver. Por exemplo, tenant2-m6tyz |
Outros campos em tokens de ID JWT
Também é possível acessar os seguintes campos auth.token:
| Declarações de tokens personalizados | ||
|---|---|---|
alg |
Algoritmo | "RS256" |
iss |
Emissor | Endereço de e-mail da conta de serviço do seu projeto |
sub |
Assunto | Endereço de e-mail da conta de serviço do seu projeto |
aud |
Público | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Hora de emissão | A hora atual, em segundos, desde a época do UNIX |
exp |
Tempo de expiração |
O tempo, em segundos, desde a época do UNIX, em que o token expira. Pode ser no máximo 3.600 segundos depois de iat.
Observação: ele controla o tempo apenas quando o token personalizado expira. No entanto, quando você faz o login de um usuário utilizando signInWithCustomToken(), ele permanece conectado ao
dispositivo até que a sessão seja invalidada ou que o usuário se desconecte.
|
<claims> (opcional) |
Declarações personalizadas opcionais a serem incluídas no token, que podem ser acessadas por
auth.token (ou request.auth.token) em
expressões. Por exemplo, se você criar uma declaração personalizada
adminClaim, poderá acessá-la com
auth.token.adminClaim.
|
|