Tutorial do schema
Tutorial do schemaLição 5: Personalizando conteúdo para diferentes usuários

Lição 5: Personalizando conteúdo para diferentes usuários

Podemos recuperar uma resposta diferente em um campo dependendo de algum dado consultado, como os papéis do usuário logado.

Query GraphQL para personalizar conteúdo para diferentes usuários

Esta query GraphQL recupera o conteúdo da publicação, adicionando um link "Editar esta publicação" ao final do conteúdo apenas para o usuário administrador:

query InitializeDynamicVariables
  @configureWarningsOnExportingDuplicateVariable(enabled: false)
{
  isAdminUser: _echo(value: false)
    @export(as: "isAdminUser")
    @remove
}
 
query ExportConditionalVariables
  @depends(on: "InitializeDynamicVariables")
{
  me {
    roleNames @remove
    isAdminUser: _inArray(
      value: "administrator",
      array: $__roleNames
    )
      @export(as: "isAdminUser")
  }
}
 
query RetrieveContentForAdminUser($postId: ID!)
  @depends(on: "ExportConditionalVariables")
  @include(if: $isAdminUser)
{
  post(by: { id : $postId }) {
    originalContent: content @remove
    wpAdminEditURL @remove
    content: _sprintf(
      string: "%s<p><a href=\"%s\">%s</a></p>",
      values: [
        $__originalContent,
        $__wpAdminEditURL,
        "(Admin only) Edit post"
      ]
    )
  }
}
 
query RetrieveContentForNonAdminUser($postId: ID!)
  @depends(on: "ExportConditionalVariables")
  @skip(if: $isAdminUser)
{
  post(by: { id : $postId }) {
    content
  }
}
 
query ExecuteAll
  @depends(on: [
    "RetrieveContentForAdminUser",
    "RetrieveContentForNonAdminUser"
  ])
{
  id @remove
}

Para usuários administradores, a resposta será:

{
  "data": {
    "user": {
      "isAdminUser": true
    },
    "post": {
      "content": "\n<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!<\/p>\n<p><a href=\"https:\/\/mysite.com\/wp-admin\/post.php?post=1&amp;action=edit\">(Admin only) Edit post<\/a><\/p>"
    }
  }
}

Para usuários não administradores, a resposta será:

{
  "data": {
    "user": {
      "isAdminUser": false
    },
    "post": {
      "content": "\n<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!<\/p>\n"
    }
  }
}

Deixar o servidor GraphQL (considerando todas as possíveis condições) calcular dinamicamente o valor necessário para um campo:

  • Simplifica a lógica da aplicação, pois há uma única fonte de verdade, o código se torna DRY e os clientes não precisam mais implementar a lógica correspondente
  • Torna a aplicação mais confiável, especialmente quando múltiplos clientes acessam dados do servidor, pois implementações diferentes da mesma lógica podem não ser idênticas, podendo levar a bugs (ainda mais quando os clientes são baseados em tecnologias diferentes, como JavaScript para um site, Java para um app Android, Swift para um app iPhone, entre outros)

Passo a passo: criando a query GraphQL

Abaixo está a análise detalhada de como a query funciona.

Verificando se o usuário é administrador

Esta query verifica se o usuário logado possui o papel "administrator" e exporta essa condição na variável dinâmica $isAdminUser:

query
{
  me {
    roleNames
    isAdminUser: _inArray(
        value: "administrator",
        array: $__roleNames
    )
      @export(as: "isAdminUser")
  }
}

Execução condicional de operações

Quando a Execução de Múltiplas Queries está habilitada, as diretivas @include e @skip também podem ser aplicadas a operações. Dessa forma, podemos executar ou não uma operação dependendo do valor de alguma variável dinâmica.

Na query abaixo, apenas uma das duas operações será executada:

  • RetrieveContentForAdminUser é executada somente quando $isAdminUser é true
  • RetrieveContentForNonAdminUser é executada somente quando $isAdminUser é false
query RetrieveContentForAdminUser
  @depends(on: "ExportConditionalVariables")
  @include(if: $isAdminUser)
{
  # ...
}
 
query RetrieveContentForNonAdminUser
  @depends(on: "ExportConditionalVariables")
  @skip(if: $isAdminUser)
{
  # ...
}

Vamos fornecer duas respostas diferentes para o campo content da publicação dependendo se o usuário é administrador ou não:

  • A primeira operação usa content como alias e calcula o valor do campo dinamicamente, combinando os campos originalContent e wpAdminEditURL via _sprintf
  • A segunda operação recupera o campo content diretamente
query RetrieveContentForAdminUser($postId: ID!)
  @depends(on: "ExportConditionalVariables")
  @include(if: $isAdminUser)
{
  post(by: { id : $postId }) {
    originalContent: content
    wpAdminEditURL
    content: _sprintf(
      string: "%s<p><a href=\"%s\">%s</a></p>",
      values: [
        $__originalContent,
        $__wpAdminEditURL,
        "(Admin only) Edit post"
      ]
    )
  }
}
 
query RetrieveContentForNonAdminUser($postId: ID!)
  @depends(on: "ExportConditionalVariables")
  @skip(if: $isAdminUser)
{
  post(by: { id : $postId }) {
    content
  }
}

Adicionando a operação a ser executada

Agora temos duas operações que podem ser executadas, porém podemos fornecer apenas um ?operationName=... ao executar a query.

Então, adicionamos a operação ExecuteAll que depende tanto de RetrieveContentForAdminUser quanto de RetrieveContentForNonAdminUser, contendo o campo simples id (porque precisamos consultar algo na operação):

query ExecuteAll
  @depends(on: [
    "RetrieveContentForAdminUser",
    "RetrieveContentForNonAdminUser"
  ])
{
  id
}

Ao invocar o endpoint com ?operationName=ExecuteAll, ambas as operações serão carregadas, porém apenas uma delas será efetivamente executada.

Removendo dados desnecessários

O passo final é remover todos os campos que são auxiliares (e que, portanto, não precisamos imprimir na resposta) via @remove.

A query GraphQL consolidada é:

query InitializeDynamicVariables
  @configureWarningsOnExportingDuplicateVariable(enabled: false)
{
  isAdminUser: _echo(value: false)
    @export(as: "isAdminUser")
    @remove
}
 
query ExportConditionalVariables
  @depends(on: "InitializeDynamicVariables")
{
  me {
    roleNames @remove
    isAdminUser: _inArray(
        value: "administrator",
        array: $__roleNames
    )
      @export(as: "isAdminUser")
  }
}
 
query RetrieveContentForAdminUser($postId: ID!)
  @depends(on: "ExportConditionalVariables")
  @include(if: $isAdminUser)
{
  post(by: { id : $postId }) {
    originalContent: content @remove
    wpAdminEditURL @remove
    content: _sprintf(
      string: "%s<p><a href=\"%s\">%s</a></p>",
      values: [
        $__originalContent,
        $__wpAdminEditURL,
        "(Admin only) Edit post"
      ]
    )
  }
}
 
query RetrieveContentForNonAdminUser($postId: ID!)
  @depends(on: "ExportConditionalVariables")
  @skip(if: $isAdminUser)
{
  post(by: { id : $postId }) {
    content
  }
}
 
query ExecuteAll
  @depends(on: [
    "RetrieveContentForAdminUser",
    "RetrieveContentForNonAdminUser"
  ])
{
  id @remove
}