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&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:
RetrieveContentForAdminUserse ejecuta sólo cuando$isAdminUserestrueRetrieveContentForNonAdminUserse ejecuta sólo cuando$isAdminUseresfalse
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
contentcomo alias y calcula el valor del campo dinámicamente, concatenando los camposoriginalContentywpAdminEditURLmediante_sprintf - La segunda operación obtiene el campo
contentdirectamente
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
}