@communecter/cocolight-api-client v1.0.48
Cocolight API Client
Ce module fournit un client JavaScript prêt à l'emploi pour interagir avec l'API Cocolight. Il encapsule la gestion des appels HTTP, l'authentification, la validation des schémas, la gestion des erreurs, ainsi qu'un ensemble de normalisations des données pour simplifier l'intégration côté client.
📦 Installation
npm install @communecter/cocolight-api-client🧭 Objectif
Ce client facilite l'intégration avec l'API Cocolight en offrant :
- Des appels simplifiés avec
axios - Un système de validation des entrées/sorties avec AJV
- La gestion automatique du token d'accès et du token de rafraîchissement
- Un circuit breaker configurable
- Un logger intégré avec Pino
- Des outils de transformation de données compatibles MongoDB/EJSON
- La gestion des appels API à partir de métadonnées JSON (endpoints)
🧱 Architecture
Le projet est structuré autour des fichiers suivants :
src/
ApiClient.js # Client principal : logique d'appel, authentification, validation, transformation
EJSONType.js # Support pour les ObjectID MongoDB avec EJSON
endpoints.module.js # Fichier généré avec les définitions d'endpoints (voir ci-dessous)
error.js # Erreurs personnalisées (ApiClientError, CircuitBreakerError)
package.json # Dépendances, scripts, métadonnéesimports
ESM
import Cocolight from "@communecter/cocolight-api-client";
const { Api, ApiClient, tokenStorageStrategy } = Cocolight;CommonJS
const { ApiClient, Api, tokenStorageStrategy } = require("@communecter/cocolight-api-client").default;🔗 Intégration via CDN
Vous pouvez inclure le client directement dans une page HTML :
<script src="https://cdn.jsdelivr.net/npm/@communecter/cocolight-api-client@latest/dist/cocolight-api-client.browser.js"></script>
<script>
const client = new CocolightApiClient.ApiClient({
baseURL: "https://www.communecter.org"
});
client.callEndpoint("AUTHENTICATE_URL", {
email: "EMAIL",
password: "PASSWORD"
}).then(res => {
const { accessToken, refreshToken, user } = res.data;
console.log("✅ Authentifié :", user.username);
})
.then(() => {
return client.callEndpoint("ME_INFO_URL");
})
.then(res => {
console.log("👤 Profil utilisateur :", res.data);
})
.then(() => {
console.log("userId :", client.userId);
})
.catch(err => console.error("Erreur :", err));
</script>🔧 Utilisation de base
import { ApiClient } from "@communecter/cocolight-api-client";
const client = new ApiClient({
baseURL: "https://mon-api.com"
});
try {
const authResponse = await client.callEndpoint("AUTHENTICATE_URL", {
email: "EMAIL",
password: "PASSWORD"
});
const { accessToken, refreshToken, user } = authResponse.data;
console.log("✅ Authentifié :", user.username);
const meResponse = await client.callEndpoint("ME_INFO_URL");
console.log("👤 Profil utilisateur :", meResponse.data);
console.log("userId :", client.userId);
} catch (error) {
console.error("❌ Erreur durant la session :", error.message, error.details);
}📜 API détaillée
new ApiClient(options)
| Option | Type | Description |
|---|---|---|
baseURL (requis) | string | URL de base de l'API |
accessToken | string | Token d'accès initial |
refreshToken | string | Token de rafraîchissement |
refreshUrl | string | URL pour rafraîchir le token (défaut : /api/cocolight/refreshtoken) |
endpoints | Array | Liste des endpoints (par défaut : endpoints.module.js) |
timeout | number | Timeout en ms (défaut : 30000) |
debug | boolean | Active le logger debug (défaut : false) |
maxRetries | number | Nombre de tentatives max (défaut : 0) |
circuitBreakerThreshold | number | Seuil d'erreurs avant blocage (défaut : 5) |
circuitBreakerResetTime | number | Délai de réactivation (en ms, défaut : 60000) |
fromJSONValue | boolean | Applique EJSON.fromJSONValue sur les réponses (défaut : true) |
Méthodes principales
callEndpoint(constant, data, transform, validate)
Effectue un appel à un endpoint défini via endpoints.module.js.
constant: nom unique du endpointdata: objet avecpathParamset données du corpstransform:true(par défaut),false, ou fonction de transformationvalidate:true(par défaut), permet de valider la réponse via AJV
setToken(token) / getToken()
Gère le token d'accès.
setRefreshToken(rt) / getRefreshToken()
Gère le token de rafraîchissement.
resetSession()
Réinitialise la session utilisateur.
Événements
refreshSuccess— déclenché après un rafraîchissement réussivalidationError— déclenché si AJV détecte des erreurssessionReset— déclenché parresetSession()
🛠️ Scripts disponibles
Depuis package.json :
npm run test— Lance les tests via Jestnpm run exemple— Lance un exemplenpm run lint/lint:fix— Vérifie et corrige le code avec ESLintnpm run build— Génère les builds navigateur + Node via Webpacknpm run generate:*— Génère les modules, documentation ou données de test depuis les fichiers JSON d’API
🧩 Dépendances principales
axios&axios-retry— pour les appels HTTP robustesajv&ajv-formats— pour la validation JSON Schemaejson— pour la compatibilité MongoDB (ObjectID, dates...)pino— logger performant, compatible navigateurevents— pour la gestion des événements custom côté client
🗃️ Format des endpoints
Chaque endpoint dans endpoints.module.js suit le schéma :
{
constant: "GET_USER_INFO",
method: "GET",
path: "/api/users/{userId}",
auth: "bearer",
pathParams: { type: "object", properties: { userId: { type: "string" } }, required: ["userId"] },
request: { ...schemaAjv },
responses: { "200": { ...schemaAjv } },
postActions: [
{ type: "setToken", path: "accessToken" },
{ type: "setUserId", path: "user._id" }
]
}🔒 Sécurité et circuit breaker
Un circuit breaker est intégré :
- Blocage temporaire après trop d’échecs (
circuitBreakerThreshold) - Réactivation après un délai (
circuitBreakerResetTime) - Journalisation complète avec
pino
🧪 Validation AJV
Chaque appel est validé avant (requête) et après (réponse) via AJV. En cas d’erreur, l’événement validationError est déclenché avec les détails.
🔄 Rafraîchissement automatique
Si une réponse retourne 401, le client tente automatiquement un appel POST vers refreshUrl avec le refreshToken, et réessaie l’appel initial si réussi.
🧼 Transformation des données
Les réponses sont normalisées :
- Champs dates, images, IDs MongoDB
- Structures communes comme
results,news,notif,replies, etc. - Conversion EJSON via
EJSON.fromJSONValue()
🧙 Valeurs dynamiques
Dans les données pathParams, il est possible d’utiliser des alias dynamiques :
pathParams: {
userId: "@userId",
accessToken: "@accessToken"
}🎩 API de façade : Api
La classe Api fournit une interface unifiée pour gérer les utilisateurs, organisations, projets et actualités. Elle encapsule les appels à ApiClient et permet de manipuler les entités comme des objets métier avec des méthodes pratiques.
🧪 Authentification
Api.userLogin(email, password, options)
Crée une instance d’Api authentifiée.
const api = await Api.userLogin("john@doe.com", "password123", { baseURL: "https://api.monapp.com" });
const user = await api.me();Api.userApi(options)
Retourne une instance UserApi si tu veux gérer manuellement l’authentification :
const userApi = Api.userApi({ baseURL: "..." });
const user = await userApi.login("email", "mdp");🔐 Session et utilisateur courant
api.me()
Retourne l'utilisateur actuellement connecté (User).
const user = await api.me();
console.log(user.data.email);👤 Utilisateurs
api.user(userData)
Crée une instance User (autre que le connecté).
const otherUser = await api.user({ slug: "caroline" });
console.log(otherUser.data.description);🏛️ Organisations
api.organization({ id | slug })
Retourne une instance d’Organization. Récupère automatiquement le profil public.
const orga = await api.organization({ slug: "asso-verte" });
console.log(orga.data.name);🏗️ Projets
api.project({ id | slug })
Retourne une instance Project. Récupère automatiquement le profil public.
const projet = await api.project({ id: "647..." });📦 Entités métiers
Les entités suivantes partagent une API commune grâce aux mixins : User, Organization, Project, News.
Propriétés
| Propriété | Description |
|---|---|
data | Proxy combiné serverData + draftData |
draftData | Données modifiables avant save() |
initialDraftData | Snapshot initial pour détection des changements |
serverData | Dernières données serveur |
isConnected | Vrai si ApiClient a un token |
userId | ID de l'utilisateur connecté |
isMe | Vrai si l'entité correspond à l'utilisateur courant |
Méthodes génériques
entity.save()
Sauvegarde les données via les blocs modifiés (UPDATE_BLOCK_*, ADD_*).
entity.refresh()
Recharge les données depuis le serveur.
entity.hasChanges()
Retourne true si le draft est différent du snapshot initial.
✏️ Méthodes d’édition (communes à toutes les entités)
| Méthode | Description |
|---|---|
updateDescription | Met à jour les champs shortDescription, description, descMentions |
updateInfo | Nom, email, téléphone, etc. |
updateSocial | Réseaux sociaux (Facebook, GitHub...) |
updateLocality | Adresse, géolocalisation |
updateSlug | Slug de l’URL |
updateImageProfil | Upload de l’avatar |
📰 Actualités (News)
Créées à partir d’un User, Organization ou Project.
Création
const news = await orga.news();
news.data.text = "Nouvelle actu !";
await news.save();Gestion
| Méthode | Description |
|---|---|
addMention({ slug \| id }) | Ajoute une mention à la news |
addImage(file) | Ajoute une image (via validation MIME) |
addFile(file) | Ajoute un fichier (PDF, CSV...) |
delete() | Supprime la news |
refresh() | Recharge la news |
get() | Récupère les données à partir de l’ID |
🔄 Utilisation des schémas de validation (AJV)
Toutes les entités sont basées sur les constantes de schéma :
ADD_*UPDATE_BLOCK_*PROFIL_IMAGE
Ces constantes sont mappées automatiquement pour les appels save(), updateX(), etc.
✅ Exemple : mise à jour d’un projet
const projet = await api.project({ slug: "bio-bazar" });
projet.data.description = "Nouveau descriptif de mon projet.";
if (projet.hasChanges()) {
await projet.save();
}👤 API : Utilisateur (User)
Une instance User offre un ensemble de méthodes métier pour interagir avec les projets, organisations et actualités de l’utilisateur.
🔍 Chargement
const user = await api.user({ slug: "caroline" });
await user.get();🏭 Création d'entités depuis User
Un utilisateur peut créer :
➕ Organisation
const orga = await user.organization({ name: "Ma nouvelle asso" });
await orga.save(); // appelle ADD_ORGANIZATION puis rafraîchit les données➕ Projet
const projet = await user.project({ name: "Mon projet citoyen" });
await projet.save(); // appelle ADD_PROJECT➕ Actualité
const news = await user.news({ text: "Hello world 🌍" });
await news.save(); // appelle ADD_NEWS📦 Récupération des projets de l'utilisateur
user.getProjects()
Retourne la liste des projets créés ou co-administrés par l’utilisateur.
const { results: projets } = await user.getProjects();
console.log("Projets liés à l'utilisateur :", projets.map(p => p.data.name));🧑🤝🧑 Récupération des organisations de l'utilisateur
user.getOrganizations()
Retourne les organisations où il est membre (admin ou non).
const { results: orgs } = await user.getOrganizations();
console.log("Organisations :", orgs.map(o => o.data.name));📰 Actualités associées
user.getNews()
Retourne toutes les actualités liées à l’utilisateur.
const newsList = await user.getNews({ indexStep: 5 });user.news(newsData)
Crée une nouvelle actualité, ou charge une existante si id est fourni.
const actu = await user.news({ text: "Ceci est une nouvelle actu" });
await actu.save();⚙️ Mise à jour du profil utilisateur
Les méthodes updateX disponibles sont :
updateDescription(data)updateInfo(data)updateSocial(data)updateLocality(data)updateSlug({ slug })updateImageProfil({ profil_avatar })updateSettings({ type, value })
🔑 Sécurité et gestion de compte
Modifier mot de passe
await user.changePassword({
oldPassword: "secret1",
newPassword: "secret2",
newPassword2: "secret2"
});Supprimer son compte
await user.delete({ reason: "Je souhaite quitter la plateforme" });Licence
MIT
👤 Auteur
Thomas Craipeau
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago