// BLOG
Kirby CMS - Lire ses données via l'API à l'aide du plugin KQL
Kirby nous permet d'accéder à nos données via une API. Pour faciliter l'accès à ces données via l'API, l'équipe Kirby a développé un plugin appelé KQL que je vais vous présenter dans cet article.
Introduction
Les initiales KQL signifient "Kirby Query Language". En effet, le plugin KQL met à notre disposition un language de requêtage des données qui est un mixte entre REST et GraphQL. Attention, le plugin KQL ne permet pas de mutations des données (creation, mise à jour, suppression) mais seulement d'accéder aux données pour ensuite les afficher ou les stocker dans un fichier CSV par exemple. Vous ne pourrez donc pas faire du CRUD à l'aide ce plugin. Pour utiliser ce plugin, commencez par l'installer, puis mettez en place l'authentification pour autoriser l'accès à l'API REST de Kirby.
Authentification
Pour mettre en place une authentification, il y a deux approches possibles selon le cas d'utilisation :
1er cas - Vous allez faire des appels à l'API depuis le frontend de votre propre site/nom de domaine.
Cela peut être le cas si vous utilisez Kirby CMS en mode headless c'est à dire si vous utilisez le CMS Kirby pour gérer uniquement la gestion des données et des utilisateurs. L'affichage des données est géré par un framework type Vue ou un générateur de site statique par exemple.
Dans ce cas nous utiliserons une authentification par Session et Token CSRF
Le token CSRF peut être généré par la fonction d'aide csrf()
mis à disposition par Kirby. Il devra ensuite être passé comme valeur de l'option d'en-tête X-CSRF
à chaque requête.
Voyons un exemple (ici en JavaScript) :
<?php
// projet_kirby/site/templates/default.php
?>
<html>
<head>
<title>API Example</title>
</head>
<body>
<script>
const csrf = "<?= csrf() ?>";
fetch("/api/pages/example", {
method: "GET",
headers: {
"X-CSRF" : csrf
}
})
.then(response => response.json())
.then(response => {
const page = response.data;
// do something with the page data
})
.catch(error => {
// something went wrong
});
</script>
</body>
</html>
2eme cas - Vous allez faire des appels à l'API depuis un serveur distant
Vous souhaitez que les données de votre site web soient disponibles pour un autre site web afin qu'il puisse les afficher sur ses propres pages.
Dans ce cas nous utiliserons une authentification HTTP basique
Pour utiliser une authentification basique, il faut commencer par l'indiquer dans le fichier de configuration de Kirby, la valeur true
passée à basicAuth
activera l'authentification :
<?php
// /site/config/config.php
return [
'api' => [
'basicAuth' => true
]
];
Pour fonctionner, il faut que la requête se fasse à travers un protocole https
à moins que vous ayez activé l'option allowInsecure
de la facon suivante :
<?php
// /site/config/config.php
return [
'api' => [
'basicAuth' => true,
'allowInsecure' => true
]
];
Pour des raisons de sécurité, n'activez pas l'option allowInsecure
en production mais seulment dans un environnement de développement.
Vous devrez également indiquer dans le code qui requête votre API le "login" et "password" d'un utilisateur Kirby ayant le droit d'accès au panel de Kirby. Une bonne pratique serait de créer un rôle spécifique par exemple ici un rôle "apiuser" (mais vous pouvez lui donner le nom que vous voulez) et de définir ses permissions de sorte qu'il n'est le droit que d'accéder au panel :
# /site/blueprints/users/apiuser.yml
title: API Authentification
description: The API user is used to fetch data from the API.
permissions:
access:
panel: true
users: false
site: false
site:
update: false
pages:
create: false
changeTemplate: false
changeTitle: false
changeURL: false
hide: false
sort: false
update: false
delete: false
users:
create: false
createAvatar: false
deleteAvatar: false
changeName: false
changeEmail: false
changePassword: false
changeRole: false
delete: false
update: false
files:
create: false
changeName: false
delete: false
replace: false
update: false
Vous pouvez maintenant créer un utilisateur avec le rôle "apiuser" et utiliser son login/password dans votre code pour accéder à l'API depuis un autre serveur/site/domain distant.
Voyons un exemple (ici en PHP) :
<?php
$user = "apiuser@mail.com";
$pass = "my_super_safe_password";
$request = Remote::request( "https://yoursite.com/api/query" , [
'method' => 'POST',
'data' => [
'query' => "page('notes').children",
'select' => [
"title",
"date" => "page.date.toDate('d.m.Y')"
]
],
'headers' => [
'Authorization: Basic ' . base64_encode( $user . ':' . $pass ),
'Content-Type: application/json'
]
]);
On utilise ici la classe Remote de Kirby qui disposent de plusieurs méthodes static dont request
qui permet d'envoyer une requête. A noter qu'on aurait pu également s'authentifier et requêter un "endpoint" de l'API en JavaScript à l'aide de la fonction Fetch()
.
Utilisation de KQL
Maintenant que nous avons installé le plugin KQL et vue comment mettre en place l'authentification, nous allons pouvoir voir plus en détail la façon d'utiliser les fonctionnalités du plugin KQL pour sélectionner les données qui nous intéressent.
Query
L'instruction Query
permet d'indiquer les données que l'on souhaite récupérer. Il peut s'agir de pages, de users, de fichiers, de champs ... et la synthaxe utilisée pour récupérer ces données est très proche de celle habituellement utilisée dans Kirby dans les templates, les controllers, les snippets ou les blueprints.
Généralement, les Query
retournent des collections c'est à dire des éléments de même types (pages, users, fichiers ...)
Par exemple, si on veut récupérer toutes les pages enfants (les articles) de la page blog, on écrira la Query
de la façon suivante :
'query' => "page('blog').children",
Vous pouvez utiliser l'instruction Query
sans la compléter par l'instruction Select
. Dans ce cas KQL récupérera l'information qu'il jugera la plus pertinente. Dans l'exemple précédent, la Query page('blog').children
sans instruction Select
, retournera les ID des pages enfants de la page 'blog'.
Dans votre Query
, vous pouvez utiliser des méthodes de Kirby comme filterBy()
, sort()
... pour filtrer vos résultats ou des méthodes de champs comme upper() ... pour appliquer une transformation aux données récupérées.
Cette page de référence vous permettra de voir l'ensemble des objets et méthodes disponibles dans Kirby.
Select
L'instruction Select
vient compléter l'instruction Query
. Alors que l'instruction Query
peux s'utiliser seul, l'instruction Select
ne le peux pas car elle s'applique directement sur l'instruction Query
.
L'instruction Select
va nous permettre d'indiquer précisement les informations que l'on souhaite récupérer sur les éléments qui ont été retournés par la Query
. Ces informations sont généralement des propriétés ou des champs.
Par exemple, si je veux récupérer le titre et l'URL des articles de mon blog, je vais passer à l'instruction Select
un tableau avec les champs ou propriétés qui m'intéressent :
<?php
'query' => "page('blog').children",
'select' => [
"title",
"url"
],
Si nous écrivons notre Query/Select en JavaScript, nous pouvons passer à l'instruction Select
un tableau ou un objet.
<script>
// Tableau
const response = await $fetch(api, {
method: "post",
body: {
query: "site.children",
select: ["title", "url"],
},
headers,
});
// Object
const response = await $fetch(api, {
method: "post",
body: {
query: "site.children",
select: {
title: true,
url: true,
},
},
headers,
});
</script>
Executer des méthodes
Comme pour les Query
, nous pouvons appliquer des méthodes Kirby aux champs ou propriétés appelés dans l'instruction Select
.
<?php
'query' => "page('blog').children",
'select' => [
'title' => 'page.title.upper',
'url'
],
Sous-requêtes
Au sein d'une instruction Select
il est possible d'executer des sous-requêtes qui retournent des collections d'éléments.
Par exemple, on peut faire une requête qui retourne des sous-pages et pour chacune de ces sous-pages faire une sous-requête qui retournera une collection de toutes les images liées.
<?php
'query' => "page('blog').children",
'select' => [
'images' => 'page.images',
],
Sous-requêtes avec instruction Select
Nous avons également la possibilité d'imbriquer des instructions Query
/Select
<?php
'query' => "page('blog').children",
'select' => [
'images' => [
'query' => "page.images",
'select' => [
'filename',
],
],
],
Pagination
Lorsqu'une requête Query
renvoie une collection (pages, users, files ...), une pagination est par défaut mise en place qui limite le resultat à 100 entrées.
Limit
Vous pouvez contrôler cette limite de la façon suivante :
<?php
'query' => "page('blog').children",
'pagination' => [
'limit' => '1'
],
'select' => [
'title',
'url'
],
],
Page
Vous pouvez également choisir sur quelle page de la pagination vous placer :
<?php
'query' => "page('blog').children",
'pagination' => [
'page' => '2',
'limit' => '1'
],
'select' => [
'title',
'url'
],
Pagination dans les sous-requêtes
Ce contrôle de la pagination peut également se faire au niveau des sous-requêtes :
<?php
'query' => "page('blog').children",
'query' => "page('notes').children",
'select' => [
'title' => 'page.title',
'images' => [
'query' => 'page.images',
'pagination' => [
'page' => '2',
'limit' => '5',
],
'select' => [
'filename',
],
],
],
],
Plusieurs requêtes dans un seul appel
Avec le système d'instruction Query
/Select
vous pouvez effectuer autant de requêtes que vous le souhaitez dans un seul appel à l'API :
<?php
'query'=> "site",
'select' => [
'title' => "site.title",
'url' => "site.url",
'notes' => [
'query' => "page('notes').children.listed",
'select' => [
'title',
'url',
'date' => "page.date.toDate('d.m.Y')",
'text' => "page.text.kirbytext",
],
],
'photography' => [
'query' => "page('photography').children.listed",
'select' => [
'title',
'images' => [
'query' => "page.images",
'select' => [
'url',
'alt',
'caption'=> "file.caption.kirbytext",
],
],
],
],
'about' => [
'text' => "page.text.kirbytext",
],
],
Permettre l'accès à des méthodes personnalisées
Par défaut, KQL n'autorise l'accès qu'aux méthodes mises à disposition dans Kirby. Si vous avez mis en place des méthodes personnalisées par exemple dans des models ou lors de la surcharge de méthodes de page, celle ci ne sont pas accessibles lors de votre requêtage.
Pour autoriser l'accès à vos méthodes personnalisées dans une requête KQL, deux solutions :
L'indiquer dans le fichier de configuration de Kirby
<?php
// /site/config/config.php
return [
'kql' => [
'methods' => [
'allowed' => [
'MyCustomPage::myCustomMethod'
]
]
]
];
L'indiquer sous forme de commentaire dans la définission de votre méthode :
Avec le mot clé @kql-allowed
<?php
// /site/models/MyCustomPage.php
class MyCustomPage extends Page
{
/**
* @kql-allowed
*/
public function myCustomMethod()
{
return ...;
}
}
Bloquer des méthodes de Classe
Si vous le souhaitez, vous pouvez interdire l'accès dans les requêtes à des méthodes de Classe Kirby qui sont disponibles par défaut :
<?php
// /site/config/config.php
return [
'kql' => [
'methods' => [
'blocked' => [
'Kirby\Cms\Page::url'
]
]
]
];
Bloquer des Classes
Vous pouvez être plus radical dans vos interdictions en interdisant l'accès aux méthodes d'une Classe entière :
<?php
// /site/config/config.php
return [
'kql' => [
'classes' => [
'blocked' => [
'Kirby\Cms\User'
]
]
]
];
Conclusion
Le plugin KQL est un superbe outil pour requêter l'API de Kirby de façon simple et précise grâce à son système très souple de Query
/Select
. Ce plugin étant développé et maintenue par l'équipe de Kirby, vous pouvez avoir confiance dans sa qualité. Si vous voulez vous exercer à requêter des données via KQL, vous pouvez utiliser le "Playground" en ligne mis à disposition par Kirby sur le Starterkit.
Dans cet article, j'ai privilégié l'utilisation de KQL dans une synthaxe PHP, si vous souhaitez voir des exemples de code de l'utilisation de KQL en JavaScript, je vous invite à consulter la documentation officielle de Kirby sur KQL.
Sachez également que ce n'est pas la seule manière d'exposer ces données vers l'exterieure. Vous pouvez aussi utiliser les représentations de contenu qui affichent vos données au format JSON via une simple URL.