Skip to Content

Chapitre 9.3 — Les fonctions externes du core

Partie 9 : Web Services — Chapitre 3/5 Public : dev Next.js/React. On a l’architecture (9.1) et un token sécurisé (9.2) ; on appelle maintenant les fonctions livrées par Moodle. Version de référence : Moodle 5.2.

⏱️ TL;DR

  • Moodle livre des milliers de fonctions externes couvrant l’essentiel : cours, inscriptions, utilisateurs, notes, contenus, calendrier, messages…
  • Le nommage est frankenstyle : core_<domaine>_<action> (core_course_get_courses) ou <plugin>_<action> (mod_forum_get_forums_by_courses, gradereport_user_get_grade_items).
  • La doc API intégrée (Web services → Documentation de l’API, par service) donne la signature exacte de chaque fonction : paramètres (types, obligatoires), et structure de retour. C’est votre contrat.
  • Appel REST : POST /webservice/rest/server.php avec wstoken, wsfunction, moodlewsrestformat=json, et les args. Les paramètres imbriqués suivent une notation spéciale (courseids[0]=2).
  • Fonctions phares : core_webservice_get_site_info (test/handshake), core_course_get_courses, core_enrol_get_users_courses, enrol_manual_enrol_users, core_user_get_users, gradereport_user_get_grade_items, core_course_get_contents.
  • Toujours vérifier la présence d’un exception dans le corps (HTTP 200 trompeur, ch. 9.1).
  • Une fonction ne renvoie/agit que dans la limite des capabilities du token (ch. 9.2).

🎯 Objectifs

  • Trouver les fonctions du core et lire leur signature dans la doc intégrée.
  • Comprendre le nommage et le format de réponse.
  • Appeler en REST (curl + TypeScript), y compris avec des paramètres imbriqués.
  • Réaliser les opérations courantes : lister cours, inscrire, lire notes, contenu de cours.

1. Où trouver les fonctions (et leur signature)

Ne devinez jamais une signature : Moodle documente chaque fonction, pour votre instance et votre version.

  • Documentation de l’API intégrée : Administration → Serveur → Web services → Documentation de l’API (ou par service). Pour chaque fonction du service, elle liste : le nom, la description, les paramètres (nom, type, obligatoire/optionnel, défaut) et la structure de retour (arborescence typée). C’est la source d’autorité — plus fiable que n’importe quel tutoriel, car elle reflète votre version.
  • L’API tester (Web services → API tester) : formulaire pour exécuter une fonction avec votre token et voir la réponse réelle. Idéal pour explorer avant de coder.
  • La référence en ligne : moodledev.io/docs/apis/subsystems/external/functions  et le code (classes/external/ des composants).

⚠️ Piège : les signatures évoluent entre versions (paramètres ajoutés/dépréciés). Fiez-vous à la doc API de votre instance 5.2, pas à un exemple trouvé pour une 4.x. L’API tester confirme le comportement réel.


2. Le nommage frankenstyle

Le nom d’une fonction encode son composant et son action :

FonctionComposantAction
core_course_get_coursescore_courselister des cours
core_enrol_get_users_coursescore_enrolcours d’un utilisateur
enrol_manual_enrol_usersenrol_manualinscrire (méthode manuelle)
core_user_get_userscore_userrechercher des utilisateurs
gradereport_user_get_grade_itemsgradereport_usernotes d’un utilisateur
mod_forum_get_forums_by_coursesmod_forumforums d’un cours
core_course_get_contentscore_coursecontenu (sections/activités) d’un cours

Convention : get_ = lecture, create_/update_/delete_/enrol_ = écriture. Les fonctions d’écriture exigent des capabilities plus fortes (ch. 9.2).


3. Anatomie d’un appel REST

L’endpoint : POST https://moodle.example.com/webservice/rest/server.php. Paramètres communs :

ParamètreValeur
wstokenvotre token (ch. 9.2)
wsfunctionle nom de la fonction
moodlewsrestformatjson
argsselon la signature

3.1 Le handshake : core_webservice_get_site_info

La première fonction à appeler pour valider token + connexion : elle renvoie les infos du site et les fonctions autorisées pour ce token.

curl 'https://moodle.example.com/webservice/rest/server.php' \ --data-urlencode 'wstoken=VOTRE_TOKEN' \ --data-urlencode 'wsfunction=core_webservice_get_site_info' \ --data-urlencode 'moodlewsrestformat=json'

Réponse (extrait) :

{ "sitename": "MaBoîte LMS", "username": "svc_nextjs", "userid": 42, "release": "5.2", "functions": [ {"name": "core_course_get_courses", "version": "2026042000"}, {"name": "core_enrol_get_users_courses", "version": "2026042000"} ] }

Le tableau functions liste exactement ce que ce token peut appeler (le service, ch. 9.1). Excellent point de départ de tout debug (« ma fonction n’est pas dans le service »).

3.2 Les paramètres imbriqués : la notation à connaître

Beaucoup de fonctions prennent des tableaux ou des structures. En REST (form-encoded), Moodle utilise une notation à crochets :

# core_course_get_courses avec options[ids][0]=2, options[ids][1]=5 curl 'https://moodle.example.com/webservice/rest/server.php' \ --data-urlencode 'wstoken=VOTRE_TOKEN' \ --data-urlencode 'wsfunction=core_course_get_courses' \ --data-urlencode 'moodlewsrestformat=json' \ --data-urlencode 'options[ids][0]=2' \ --data-urlencode 'options[ids][1]=5'

Pour enrol_manual_enrol_users, chaque inscription est un objet dans un tableau enrolments :

--data-urlencode 'enrolments[0][roleid]=5' \ --data-urlencode 'enrolments[0][userid]=123' \ --data-urlencode 'enrolments[0][courseid]=2'

⚠️ Piège n°1 des paramètres : la notation enrolments[0][userid]=123 doit être exacte (indices numériques, crochets imbriqués). Une erreur de structure donne une erreur de validation invalidparameter avant l’exécution. La doc API montre la structure attendue ; l’API tester génère les bons noms de champs — copiez-les.


4. Les opérations courantes (curl + TypeScript)

Passons à TypeScript, tel qu’appelé côté serveur Next.js (ch. 9.5 détaille le client). On suppose un helper callMoodle(wsfunction, args) qui POST en form-encoded — construit au chapitre 5. Ici, on se concentre sur quelles fonctions et quels paramètres.

4.1 Lister les cours d’un utilisateur

// core_enrol_get_users_courses : les cours où userid est inscrit const courses = await callMoodle('core_enrol_get_users_courses', { userid: 123, }); // → [{ id, shortname, fullname, progress, ... }, ...]

4.2 Lister/rechercher des cours

// Tous les cours (ou par ids) const all = await callMoodle('core_course_get_courses', {}); const some = await callMoodle('core_course_get_courses', { 'options[ids][0]': 2, 'options[ids][1]': 5, });

4.3 Inscrire un utilisateur (écriture)

// enrol_manual_enrol_users : inscrit userid dans courseid avec roleid await callMoodle('enrol_manual_enrol_users', { 'enrolments[0][roleid]': 5, // 5 = étudiant (par défaut) 'enrolments[0][userid]': 123, 'enrolments[0][courseid]': 2, }); // → null en cas de succès (pas de retour) ; exception sinon

Nécessite que le token porte enrol/manual:enrol sur le cours (ch. 9.2), et que la méthode d’inscription manuelle soit activée sur le cours.

4.4 Rechercher des utilisateurs

// core_user_get_users : recherche par critères const users = await callMoodle('core_user_get_users', { 'criteria[0][key]': 'email', 'criteria[0][value]': 'alice@example.com', }); // → { users: [{ id, username, fullname, email, ... }], warnings: [] }

4.5 Lire les notes d’un utilisateur dans un cours

// gradereport_user_get_grade_items : les notes détaillées const report = await callMoodle('gradereport_user_get_grade_items', { courseid: 2, userid: 123, }); // → { usergrades: [{ courseid, userid, gradeitems: [{ itemname, gradeformatted, ... }] }] }

4.6 Récupérer le contenu (structure) d’un cours

// core_course_get_contents : sections + modules du cours const contents = await callMoodle('core_course_get_contents', { courseid: 2, }); // → [{ id, name, modules: [{ id, name, modname, url, ... }] }, ...]

5. Le format des réponses (et les warnings)

Deux régularités à connaître :

  • Structures typées : chaque fonction renvoie une arborescence stable (objets/tableaux) décrite par sa doc. Les champs de texte sont déjà formatés côté serveur (external_format_string/external_format_text, ch. 9.4) — sûrs à afficher.
  • Les warnings : beaucoup de fonctions renvoient un tableau warnings à côté des données. Un warning n’est pas une exception : c’est un avertissement par élément (ex. « l’utilisateur X n’a pas pu être traité »). Inspectez warnings même en cas de succès global — sinon vous ratez des échecs partiels.
{ "users": [ { "id": 123, "fullname": "Alice" } ], "warnings": [ { "item": "user", "itemid": 999, "warningcode": "usernotfound", "message": "..." } ] }

⚠️ Piège : ignorer warnings sur une opération de masse (inscrire 500 utilisateurs) fait croire à un succès total alors que certains ont échoué. Traitez warnings comme des erreurs partielles à remonter/logger.


6. Débogage : la checklist

Quand un appel échoue :

  1. HTTP 200 mais exception dans le corps ? → lire errorcode/message (ch. 9.1).
  2. accessexception / fonction inconnue ? → la fonction n’est pas dans le service (vérifier via get_site_info.functions, ch. §3.1) ou le protocole REST n’est pas activé.
  3. required_capability / nopermissions ? → capability métier manquante sur le compte de service (ch. 9.2 §3).
  4. invalidparameter ? → structure des paramètres incorrecte (notation à crochets, §3.2) — recopier depuis l’API tester.
  5. invalidtoken ? → token faux/expiré/révoqué, ou IP non autorisée (ch. 9.2).

💡 Pour un dev React : votre réflexe « lire le status HTTP » ne suffit pas ici. Écrivez une fois un wrapper (callMoodle) qui : parse le JSON, détecte exception, et jette une erreur typée — puis vous codez comme avec une API normale. Ce wrapper est le sujet du chapitre 5.


7. Synthèse

Le core expose une API vaste et auto-documentée. La méthode fiable : explorer la doc API + l’API tester de votre instance → repérer la fonction et sa signature exacte → l’appeler en REST avec la bonne notation de paramètresvérifier l’exception et les warnings → afficher. Tout appel s’exécute dans la limite des capabilities du token. Vous savez maintenant consommer le core ; le chapitre suivant vous apprend à exposer vos propres fonctions quand le core ne suffit pas.


✏️ Exercices

Exercice 1 — Trouver la signature. Vous voulez inscrire un utilisateur. Où trouvez-vous la structure exacte des paramètres de enrol_manual_enrol_users, et pourquoi pas un blog ?

✅ Solution

Dans la Documentation de l’API intégrée de votre instance (par service), qui liste les paramètres (enrolments = tableau d’objets {roleid, userid, courseid, ...}) pour votre version 5.2, et via l’API tester qui génère les noms de champs exacts (enrolments[0][userid]). Pas un blog, car les signatures évoluent entre versions : un exemple 4.x peut être obsolète. La doc de l’instance est la source d’autorité.

Exercice 2 — Handshake. Quelle fonction appelez-vous en premier pour valider votre intégration, et qu’apprenez-vous de sa réponse ?

✅ Solution

core_webservice_get_site_info : elle valide que le token et la connexion fonctionnent, et renvoie sitename, username/userid (l’identité du token), release (version), et surtout le tableau functions = la liste exacte des fonctions que ce token peut appeler (le service). C’est le point de départ de tout debug (« ma fonction est-elle bien dans le service ? »).

Exercice 3 — Paramètres imbriqués. Traduisez en notation REST : « lister les cours d’ids 3 et 7 ». Puis dites ce qui se passe si la notation est mal formée.

✅ Solution

core_course_get_courses avec options[ids][0]=3 et options[ids][1]=7 (form-encoded, indices numériques). Si la notation est mal formée (ex. options[ids]=3,7 ou mauvais crochets), Moodle renvoie une erreur invalidparameter à la validation (execute_parameters), avant d’exécuter la fonction. Copier la structure depuis l’API tester évite ces erreurs.

Exercice 4 — Échec partiel. Vous inscrivez 500 utilisateurs ; l’appel renvoie un succès HTTP 200. Que devez-vous vérifier avant de conclure au succès total ?

✅ Solution

Le tableau warnings de la réponse : il liste les échecs partiels (utilisateurs non trouvés, cours invalides…) sans lever d’exception globale. Un HTTP 200 et l’absence d’exception signifient seulement que l’appel a été traité, pas que chaque inscription a réussi. Il faut parcourir warnings, les logger/remonter, et réconcilier. Ignorer warnings masque des échecs silencieux.

Exercice 5 — Diagnostic. Un appel renvoie {"exception":"webservice_access_exception","errorcode":"accessexception"}. Deux causes possibles ?

✅ Solution

(1) La fonction n’est pas dans le service attaché au token (vérifier via get_site_info.functions, l’ajouter au service côté admin). (2) Le protocole REST n’est pas activé ou le service est désactivé/l’utilisateur non autorisé. (Une capability métier manquante donnerait plutôt nopermissions/required_capability.) Checklist du §6 : commencer par le handshake pour isoler.


🧠 Quiz de révision

Q1. Où trouve-t-on la signature exacte d’une fonction et pourquoi cette source ?

Réponse

Dans la Documentation de l’API intégrée (par service) et l’API tester de votre instance : elles reflètent votre version 5.2 (paramètres, types, structure de retour). Les signatures évoluent entre versions, donc un exemple externe peut être obsolète.

Q2. Que signifie le nommage core_enrol_get_users_courses ?

Réponse

Frankenstyle : composant core_enrol + action get_users_courses (lecture des cours d’un utilisateur). get_ = lecture ; create_/update_/delete_/enrol_ = écriture (capabilities plus fortes).

Q3. Comment passe-t-on un paramètre tableau/objet en REST ?

Réponse

Avec la notation à crochets : options[ids][0]=3, enrolments[0][userid]=123. La structure doit être exacte (indices numériques, imbrication) ; sinon erreur invalidparameter. L’API tester génère les bons noms de champs.

Q4. Pourquoi faut-il inspecter warnings même en cas de succès ?

Réponse

Parce que warnings signale des échecs partiels (par élément) sans lever d’exception globale. Un HTTP 200 sans exception ne garantit pas que chaque élément d’une opération de masse a réussi ; ignorer warnings masque des échecs silencieux.

Q5. Quelle fonction sert de handshake et qu’apprend-on de sa réponse ?

Réponse

core_webservice_get_site_info : elle valide token/connexion et renvoie l’identité du token, la version, et la liste des fonctions autorisées (functions) — la référence pour vérifier ce que le token peut appeler.

Chapitre suivant : 04 — Créer sa propre fonction externe — exposer local_todolist en web service : la classe \core_external\external_api, le triptyque execute_parameters() / execute() / execute_returns(), la déclaration dans db/services.php, la validation typée, les capabilities, et la sortie sûre.