Tutorial del esquema
Tutorial del esquemaLección 5: Personalizar contenido para distintos usuarios

Lección 5: Personalizar contenido para distintos usuarios

Podemos obtener una respuesta distinta en un campo en función de algún dato consultado, como los roles del usuario autenticado.

Consulta GraphQL para personalizar contenido para distintos usuarios

Esta consulta GraphQL obtiene el contenido de una entrada y añade un enlace "Editar esta entrada" al final del contenido sólo para el usuario 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 usuarios administradores, la respuesta 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 usuarios no administradores, la respuesta 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"
    }
  }
}

Que el servidor GraphQL (dadas todas las posibles condiciones) calcule dinámicamente el valor requerido para un campo:

  • Simplifica la lógica de la aplicación, ya que hay una única fuente de verdad, el código se vuelve DRY y los clientes ya no necesitan implementar la lógica correspondiente
  • Hace que la aplicación sea más fiable, especialmente cuando varios clientes acceden a los datos del servidor, ya que distintas implementaciones de la misma lógica pueden no ser idénticas, lo que puede dar lugar a bugs (más aún cuando los clientes están basados en distintas tecnologías, como JavaScript para una web, Java para una app de Android, Swift para una app de iPhone, etc.)

Paso a paso: creación de la consulta GraphQL

A continuación se muestra el análisis detallado de cómo funciona la consulta.

Averiguar si el usuario es administrador

Esta consulta comprueba si el usuario autenticado tiene el rol "administrator" y exporta esta condición en la variable dinámica $isAdminUser:

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

Ejecución condicional de operaciones

Cuando Ejecución de múltiples consultas está habilitado, las directivas @include y @skip también pueden aplicarse a operaciones. De este modo podemos ejecutar o no una operación dependiendo del valor de alguna variable dinámica.

En la consulta de abajo sólo se ejecutará una de las dos operaciones:

  • RetrieveContentForAdminUser se ejecuta sólo cuando $isAdminUser es true
  • RetrieveContentForNonAdminUser se ejecuta sólo cuando $isAdminUser es false
query RetrieveContentForAdminUser
  @depends(on: "ExportConditionalVariables")
  @include(if: $isAdminUser)
{
  # ...
}
 
query RetrieveContentForNonAdminUser
  @depends(on: "ExportConditionalVariables")
  @skip(if: $isAdminUser)
{
  # ...
}

Vamos a proporcionar dos respuestas distintas para el campo content de la entrada dependiendo de si el usuario es administrador o no:

  • La primera operación usa content como alias y calcula el valor del campo dinámicamente, concatenando los campos originalContent y wpAdminEditURL mediante _sprintf
  • La segunda operación obtiene el campo content directamente
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
  }
}

Añadir la operación a ejecutar

Ahora tenemos dos operaciones que podrían ejecutarse, pero sólo podemos proporcionar un ?operationName=... al ejecutar la consulta.

Por tanto, añadimos la operación ExecuteAll, que depende de RetrieveContentForAdminUser y RetrieveContentForNonAdminUser, conteniendo el sencillo campo id (porque debemos consultar algo en la operación):

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

Invocar el endpoint con ?operationName=ExecuteAll ahora cargará ambas operaciones, pero sólo una de ellas se ejecutará realmente.

Eliminar datos innecesarios

El paso final es eliminar mediante @remove todos los campos que son auxiliares (y como tal no necesitamos imprimir su salida en la respuesta).

La consulta GraphQL consolidada es:

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
}