Terrain 17 — Web services
⏱️ TL;DR — 25 mini-jeux
⭐⭐⭐⭐→⭐⭐⭐⭐⭐pour ouvrir Moodle vers l’extérieur : activer les web services, appeler des fonctions du cœur avec un token, puis écrire ta fonction externe dans un plugin et la consommer depuis un front Next.js. C’est le projet Niveau 4 en mini-jeux — ton pont Moodle ↔ moderne.
💡 Pour un dev React — Une external function Moodle est un endpoint typé :
execute_parameters()/execute_returns()sont un schéma (comme zod/OpenAPI) que Moodle valide à l’entrée et à la sortie. Une fois le token obtenu, appeler Moodle = un simplefetch.
🕹️ Mini-jeu 1 — Activer les web services ⭐⭐⭐ 🛠️
But : ouvrir l’API. Mission : lance l’assistant Administration → Serveur → Web services → Vue d’ensemble.
✅ Solution
L’assistant (Overview) déroule pas à pas l’activation : protocole, service, utilisateur, token, test. Le chemin officiel. Chaque étape correspond aux jeux suivants.
🕹️ Mini-jeu 2 — Activer le protocole REST ⭐⭐⭐ 🛠️
But : choisir le format d’échange. Mission : active REST dans les protocoles.
✅ Solution
Serveur → Web services → Gérer les protocoles → active REST (JSON/XML). Moodle supporte aussi SOAP. REST est le plus simple à consommer depuis Next.js. Sans protocole actif, aucun appel n’est possible.
🕹️ Mini-jeu 3 — Créer un service externe ⭐⭐⭐ 🛠️
But : un regroupement de fonctions. Mission : crée un service externe « Dashboard ».
✅ Solution
Un service externe (Serveur → Web services → Services externes) regroupe les fonctions autorisées et les utilisateurs/tokens qui y accèdent. On y ajoutera des fonctions du cœur (jeu 6) et la tienne (jeu 13). Le périmètre d’exposition.
🕹️ Mini-jeu 4 — Un utilisateur de service + token ⭐⭐⭐⭐ 🛠️
But : l’authentification machine. Mission : crée un compte de service et génère un token.
✅ Solution
On crée un compte dédié (droits minimaux), on l’autorise sur le service, puis Gérer les tokens génère un jeton. Le token authentifie les appels (comme une clé d’API). ⚠️ Il porte les droits de ce compte : moindre privilège (terrain 11).
🕹️ Mini-jeu 5 — La documentation de l’API ⭐⭐⭐ 🛠️
But : explorer les fonctions. Mission : ouvre API Documentation avec ton token.
✅ Solution
La page API Documentation liste chaque fonction, sa signature (params/retours) et permet de la tester avec le token. Ton explorateur d’API intégré — indispensable avant de coder le front. Auto-générée depuis les execute_*.
🕹️ Mini-jeu 6 — Appeler une fonction du cœur ⭐⭐⭐⭐ 💻
But : premier appel réel.
Mission : appelle core_course_get_courses via REST.
Étapes :
POST /webservice/rest/server.php
?wstoken=TOKEN
&wsfunction=core_course_get_courses
&moodlewsrestformat=json✅ Solution
Tout appel REST cible webservice/rest/server.php avec wstoken, wsfunction et moodlewsrestformat=json. Moodle a des centaines de fonctions cœur (core_*, mod_*). Teste d’abord avec cURL/Postman avant Next.js (jeu 19).
🕹️ Mini-jeu 7 — Structure d’une fonction externe ⭐⭐⭐⭐⭐ 💻
But : ta propre API.
Mission : crée classes/external/get_stats.php dans un plugin local.
Étapes :
<?php
namespace local_dashboard\external;
use core_external\external_api;
use core_external\external_function_parameters;
class get_stats extends external_api {
// execute_parameters / execute / execute_returns (jeux 8-10)
}✅ Solution
Une external function est une classe dans classes/external/ étendant external_api, avec trois méthodes : execute_parameters(), execute(), execute_returns(). C’est le contrat typé de ton endpoint. (Namespaces modernes core_external\ en Moodle 4.2+.)
🕹️ Mini-jeu 8 — execute_parameters() ⭐⭐⭐⭐⭐ 💻
But : déclarer les entrées.
Mission : déclare un paramètre courseid.
Étapes :
public static function execute_parameters() {
return new external_function_parameters([
'courseid' => new external_value(PARAM_INT, 'Course id'),
]);
}✅ Solution
execute_parameters() type les entrées (Moodle les valide avant ton code). external_value(PARAM_INT, ...) = un entier requis. Comme un schéma zod : entrée invalide → rejet automatique. Ta première ligne de défense.
🕹️ Mini-jeu 9 — execute() ⭐⭐⭐⭐⭐ 💻
But : la logique, sécurisée.
Mission : implémente execute() avec validation de contexte + capability.
Étapes :
public static function execute($courseid) {
global $DB;
$params = self::validate_parameters(self::execute_parameters(), ['courseid' => $courseid]);
$context = \context_course::instance($params['courseid']);
self::validate_context($context);
require_capability('moodle/course:viewparticipants', $context);
return ['enrolled' => 42];
}✅ Solution
⚠️ Le point critique : validate_parameters + validate_context + require_capability. Les web services contournent l’UI mais pas les permissions — reproduis les vérifs (terrain 16). Une external function sans contrôle = fuite de données.
🕹️ Mini-jeu 10 — execute_returns() ⭐⭐⭐⭐⭐ 💻
But : déclarer la sortie. Mission : type la réponse. Étapes :
public static function execute_returns() {
return new external_single_structure([
'enrolled' => new external_value(PARAM_INT, 'Enrolled count'),
]);
}✅ Solution
execute_returns() type la réponse : Moodle la valide en sortie (une clé manquante ou mal typée → erreur). Contrat clair pour le consommateur. external_single_structure (objet), external_multiple_structure (liste), external_value (scalaire).
🕹️ Mini-jeu 11 — Déclarer dans db/services.php ⭐⭐⭐⭐⭐ 💻
But : exposer la fonction.
Mission : enregistre local_dashboard_get_stats.
Étapes :
<?php
$functions = [
'local_dashboard_get_stats' => [
'classname' => 'local_dashboard\external\get_stats',
'methodname' => 'execute',
'description' => 'Get course stats',
'type' => 'read',
'capabilities'=> 'moodle/course:viewparticipants',
],
];✅ Solution
db/services.php déclare la fonction (nom public = frankenstyle local_dashboard_get_stats), pointe la classe/méthode, le type (read/write) et la capability requise. Bumpe la version + purge pour l’enregistrer. Elle apparaît alors dans l’API doc.
🕹️ Mini-jeu 12 — Ajouter au service ⭐⭐⭐ 🛠️
But : rendre la fonction appelable.
Mission : ajoute local_dashboard_get_stats au service « Dashboard ».
✅ Solution
Une fonction déclarée n’est appelable que si elle est dans un service autorisé pour le token (jeu 3). On l’y ajoute (Services externes → Fonctions). Sécurité par liste blanche : rien n’est exposé par défaut.
🕹️ Mini-jeu 13 — Tester ta fonction ⭐⭐⭐⭐ 💻
But : vérifier le contrat.
Mission : teste local_dashboard_get_stats via l’API Documentation.
✅ Solution
Depuis l’API doc (jeu 5), appelle ta fonction avec un courseid et le token → réponse JSON typée. Teste aussi un cas refusé (courseid sans droit) → erreur de capability. Valide les deux chemins avant le front.
🕹️ Mini-jeu 14 — Une structure de liste ⭐⭐⭐⭐⭐ 💻
But : renvoyer un tableau d’objets. Mission : renvoie une liste de cours. Étapes :
return new external_multiple_structure(
new external_single_structure([
'id' => new external_value(PARAM_INT, 'id'),
'name' => new external_value(PARAM_TEXT, 'name'),
])
);✅ Solution
external_multiple_structure(external_single_structure([...])) type une liste d’objets — le cas le plus courant (liste de cours, de participants…). Moodle valide chaque élément. Contrat riche et sûr.
🕹️ Mini-jeu 15 — N’exposer que le permis ⭐⭐⭐⭐⭐ 💻
But : pas de fuite. Mission : vérifie que ta réponse ne contient que les champs voulus.
✅ Solution
execute_returns() filtre la sortie (les champs non déclarés sont retirés). Mais construis quand même ta réponse en n’incluant que le nécessaire (pas de mots de passe, de données d’autres users). Défense en profondeur (terrain 16).
🕹️ Mini-jeu 16 — Appeler depuis cURL ⭐⭐⭐⭐ 💻
But : valider hors Moodle. Mission : appelle ta fonction en cURL. Étapes :
curl "https://moodle.local/webservice/rest/server.php?wstoken=TOKEN&wsfunction=local_dashboard_get_stats&moodlewsrestformat=json&courseid=2"✅ Solution
cURL/Postman confirme le contrat indépendamment du front : réponse JSON, gestion d’erreur (exception). Débuguer l’API avant d’écrire le front évite de confondre bug d’API et bug de front.
🕹️ Mini-jeu 17 — Appeler depuis Next.js ⭐⭐⭐⭐⭐ 💻
But : consommer côté serveur. Mission : fetch ta fonction dans un Server Component. Étapes :
const url = `${process.env.MOODLE}/webservice/rest/server.php`
+ `?wstoken=${process.env.MOODLE_TOKEN}&wsfunction=local_dashboard_get_stats`
+ `&moodlewsrestformat=json&courseid=2`;
const stats = await (await fetch(url)).json();✅ Solution
Un Server Component (App Router) fetch directement — Moodle n’est qu’une API. Ton expertise React s’applique. ⚠️ Le token vit côté serveur (variables d’env), jamais dans le bundle client (jeu 20).
🕹️ Mini-jeu 18 — Gérer les erreurs ⭐⭐⭐⭐ 💻
But : robustesse. Mission : détecte une réponse d’erreur Moodle.
✅ Solution
En cas d’erreur, Moodle renvoie un JSON avec exception, errorcode, message (pas un code HTTP d’erreur !). Le front doit inspecter le corps (if (data.exception)) et gérer token invalide/droit manquant. Robustesse indispensable.
🕹️ Mini-jeu 19 — Le token côté serveur ⭐⭐⭐⭐⭐ 💻
But : ne jamais exposer le token.
Mission : mets MOODLE_TOKEN en variable d’environnement, appelé depuis une route/serveur.
✅ Solution
Le token n’apparaît jamais dans le navigateur (il porte des droits). Tous les appels Moodle passent par le serveur Next.js (Server Component, route handler, server action). Vérifie l’onglet réseau : le token ne doit pas y être. Règle d’or headless (terrain 16).
🕹️ Mini-jeu 20 — Web services et l’app mobile ⭐⭐⭐ 🛠️
But : comprendre l’écosystème. Mission : repère le service « Moodle mobile web service ».
✅ Solution
L’app mobile Moodle utilise les web services (service prédéfini). Comprendre ça éclaire l’importance de l’API : c’est la porte d’intégration (mobile, front headless, systèmes tiers). Ton front Next.js emprunte le même canal.
🕹️ Mini-jeu 21 — Ajax interne vs external ⭐⭐⭐⭐ 💻
But : deux usages de la même API. Mission : distingue un appel Ajax interne (dans Moodle) d’un web service externe.
✅ Solution
Les mêmes external functions servent l’Ajax interne (via core/ajax en JS, terrain 14, avec la session) et les web services externes (avec token). Écrire une external function bien faite sert les deux mondes. Élégant et réutilisable.
🕹️ Mini-jeu 22 — Journaliser les appels ⭐⭐⭐ 🛠️
But : auditer l’usage. Mission : repère les logs de web services (Rapports).
✅ Solution
Moodle journalise les appels web service (utilisateur/fonction/date). Utile pour auditer un token, diagnostiquer un abus, surveiller la charge. À croiser avec la sécurité du token (jeu 19). Traçabilité de l’API.
🕹️ Mini-jeu 23 — Versionner un service ⭐⭐⭐⭐ 💻
But : évoluer sans casser. Mission : réfléchis à comment ajouter un champ sans casser les clients.
✅ Solution
On ajoute des champs optionnels (VALUE_OPTIONAL dans external_single_structure) plutôt que d’en retirer/renommer (rupture). Pour un vrai changement, une nouvelle fonction (..._get_stats_v2). Discipline d’API publique — comme tu versionnerais une API REST.
🕹️ Mini-jeu 24 — Un mini dashboard complet ⭐⭐⭐⭐⭐ 💻
But : assembler.
Mission : un Next.js qui liste cours + inscrits via local_dashboard_get_stats, token côté serveur, erreurs gérées.
✅ Solution
Fonction externe sécurisée + service + token + front Next.js server-side + gestion d’erreur = le projet Niveau 4 en condensé. WordPress a REST natif ; Moodle a les web services — même logique de pont, ta valeur ajoutée.
🕹️ Mini-jeu 25 — Récap web services ⭐⭐⭐⭐⭐ 💻
But : capstone du terrain. Mission : WS activés (REST), service + token, une external function typée et sécurisée (validate_context + capability), testée en cURL et consommée par un Next.js (token serveur).
✅ Solution
Tu sais ouvrir Moodle proprement et le brancher à un front moderne — la compétence rare et premium (Partie 13). Dernier terrain, le sommet : un vrai outil LTI headless en Next.js (terrain 18).
Terrain suivant : 18 — LTI & headless (Next.js).