22 KiB
PersoNotes REST API Documentation
Version: v1
Base URL: http://localhost:8080/api/v1
Table des matières
- Vue d'ensemble
- Commandes CLI
- Authentification
- Formats de données
- Endpoints
- Notes publiques
- Codes de statut HTTP
- Exemples d'utilisation
Vue d'ensemble
L'API REST de PersoNotes permet de gérer vos notes Markdown via HTTP. Elle supporte :
- Listage : Récupérer la liste de toutes les notes avec métadonnées
- Lecture : Télécharger une note en JSON ou Markdown brut
- Écriture : Créer ou mettre à jour une note
- Suppression : Supprimer une note définitivement
Caractéristiques
- ✅ Versionnée :
/api/v1pour assurer la compatibilité future - ✅ Content Negotiation : Support JSON et Markdown selon le header
Accept - ✅ Idempotence : PUT crée ou met à jour (idempotent)
- ✅ Automatisation : Front matter géré automatiquement
- ✅ Ré-indexation : Recherche mise à jour automatiquement après chaque modification
- ✅ Support sous-dossiers : Organisation hiérarchique native
Commandes CLI
Le serveur inclut des commandes CLI intégrées pour gérer les notes publiques sans avoir à lancer le serveur HTTP.
Lister les notes publiques
Affiche toutes les notes qui ont été exportées en HTML public.
Commande :
./server list-public [notes-dir]
Arguments :
notes-dir(optionnel) : Chemin vers le répertoire des notes (défaut:./notes)
Exemple de sortie :
📚 Notes publiques (4):
• 2025 Learning Goals
Source: personal/learning-goals.md
Public: public/learning-goals.html
Date: 2025-11-13 20:06:21
• AI Writing Assistant
Source: archive/ai-assistant.md
Public: public/ai-assistant.html
Date: 2025-11-13 19:43:28
• API Endpoints Reference
Source: documentation/api/endpoints.md
Public: public/endpoints.html
Date: 2025-11-13 19:36:57
• Product Backlog
Source: tasks/backlog.md
Public: public/backlog.html
Date: 2025-11-13 20:13:05
Cas particuliers :
- Si aucune note n'est publique : affiche "Aucune note publique."
- Si le fichier
.public.jsonn'existe pas : affiche "Aucune note publique trouvée." - Erreur si le répertoire n'existe pas
Utilisation typique :
# Lister les notes publiques
./server list-public
# Avec un répertoire personnalisé
./server list-public /path/to/notes
# Compter les notes publiques (Linux/macOS)
./server list-public | grep -c "^•"
# Exporter la liste dans un fichier
./server list-public > public-notes-list.txt
Authentification
Version actuelle : Aucune authentification requise
⚠️ IMPORTANT : L'API n'a pas d'authentification. Si vous exposez le serveur publiquement :
- Utilisez un reverse proxy (nginx, Caddy) avec authentification
- Implémentez Basic Auth ou API Key
- Utilisez un VPN ou tunnel SSH
Formats de données
Note complète (NoteResponse)
{
"path": "projet/backend.md",
"title": "Backend API",
"content": "---\ntitle: Backend API\n...\n---\n\n# Content",
"body": "\n# Content",
"frontMatter": {
"title": "Backend API",
"date": "10-11-2025",
"last_modified": "10-11-2025:14:30",
"tags": ["projet", "backend"]
},
"lastModified": "10-11-2025:14:30",
"size": 1024
}
Métadonnées de note (NoteMetadata)
{
"path": "projet/backend.md",
"title": "Backend API",
"tags": ["projet", "backend"],
"lastModified": "10-11-2025:14:30",
"date": "10-11-2025",
"size": 1024
}
Requête de création/modification (NoteRequest)
Deux options :
Option 1 : Content complet (recommandé pour migration)
{
"content": "---\ntitle: Ma note\ntags: [test]\n---\n\n# Contenu"
}
Option 2 : Body + FrontMatter séparés (recommandé pour création)
{
"body": "\n# Mon contenu\n\nTexte ici...",
"frontMatter": {
"title": "Ma note",
"tags": ["test", "exemple"]
}
}
Erreur (ErrorResponse)
{
"error": "Bad Request",
"message": "Invalid path",
"code": 400
}
Endpoints
Lister les notes
Récupère la liste de toutes les notes avec leurs métadonnées.
Endpoint : GET /api/v1/notes
Paramètres : Aucun
Réponse : 200 OK
{
"notes": [
{
"path": "projet/backend.md",
"title": "Backend API",
"tags": ["projet", "backend"],
"lastModified": "10-11-2025:14:30",
"date": "10-11-2025",
"size": 1024
},
{
"path": "daily/2025-11-10.md",
"title": "Notes du 10 novembre",
"tags": ["daily"],
"lastModified": "10-11-2025:09:15",
"date": "10-11-2025",
"size": 2048
}
],
"total": 2
}
Exemple curl :
curl http://localhost:8080/api/v1/notes
Récupérer une note
Télécharge une note spécifique. Le format dépend du header Accept.
Endpoint : GET /api/v1/notes/{path}
Paramètres :
{path}: Chemin relatif de la note (ex:projet/backend.md)
Headers :
Accept: application/json(défaut) : Retourne JSON avec métadonnéesAccept: text/markdown: Retourne Markdown brutAccept: text/plain: Retourne Markdown brut
Réponse JSON : 200 OK
{
"path": "projet/backend.md",
"title": "Backend API",
"content": "---\ntitle: Backend API\ndate: 10-11-2025\nlast_modified: 10-11-2025:14:30\ntags:\n - projet\n - backend\n---\n\n# Backend API\n\nContenu de la note...",
"body": "\n# Backend API\n\nContenu de la note...",
"frontMatter": {
"title": "Backend API",
"date": "10-11-2025",
"last_modified": "10-11-2025:14:30",
"tags": ["projet", "backend"]
},
"lastModified": "10-11-2025:14:30",
"size": 1024
}
Réponse Markdown : 200 OK
---
title: Backend API
date: 10-11-2025
last_modified: 10-11-2025:14:30
tags:
- projet
- backend
---
# Backend API
Contenu de la note...
Erreurs :
404 Not Found: Note inexistante
Exemples curl :
# Récupérer en JSON
curl http://localhost:8080/api/v1/notes/projet/backend.md \
-H "Accept: application/json"
# Récupérer en Markdown brut
curl http://localhost:8080/api/v1/notes/projet/backend.md \
-H "Accept: text/markdown"
# Sauvegarder dans un fichier
curl http://localhost:8080/api/v1/notes/projet/backend.md \
-H "Accept: text/markdown" \
-o backend.md
Créer/Mettre à jour une note
Crée une nouvelle note ou met à jour une note existante (idempotent).
Endpoint : PUT /api/v1/notes/{path}
Paramètres :
{path}: Chemin relatif de la note (ex:projet/nouvelle-note.md)
Headers :
Content-Type: application/json: Envoyer du JSONContent-Type: text/markdown: Envoyer du Markdown brut
Body JSON :
{
"body": "\n# Ma nouvelle note\n\nContenu ici...",
"frontMatter": {
"title": "Ma nouvelle note",
"tags": ["test", "exemple"]
}
}
Ou avec content complet :
{
"content": "---\ntitle: Ma note\ntags: [test]\n---\n\n# Contenu"
}
Body Markdown brut :
# Ma nouvelle note
Contenu ici...
Réponse : 201 Created (nouvelle note) ou 200 OK (mise à jour)
{
"path": "projet/nouvelle-note.md",
"title": "Ma nouvelle note",
"content": "---\ntitle: Ma nouvelle note\n...",
"body": "\n# Ma nouvelle note\n\nContenu ici...",
"frontMatter": {
"title": "Ma nouvelle note",
"date": "10-11-2025",
"last_modified": "10-11-2025:14:35",
"tags": ["test", "exemple"]
},
"lastModified": "10-11-2025:14:35",
"size": 256
}
Comportement :
- ✅ Crée automatiquement les dossiers parents
- ✅ Génère le front matter si absent
- ✅ Met à jour
last_modifiedautomatiquement - ✅ Préserve
datepour notes existantes - ✅ Ré-indexe automatiquement pour la recherche
Erreurs :
400 Bad Request: Chemin invalide ou JSON malformé415 Unsupported Media Type: Content-Type non supporté500 Internal Server Error: Erreur d'écriture
Exemples curl :
# Créer avec JSON
curl -X PUT http://localhost:8080/api/v1/notes/projet/test.md \
-H "Content-Type: application/json" \
-d '{
"body": "\n# Test\n\nCeci est un test.",
"frontMatter": {
"title": "Note de test",
"tags": ["test"]
}
}'
# Créer avec Markdown brut
curl -X PUT http://localhost:8080/api/v1/notes/projet/simple.md \
-H "Content-Type: text/markdown" \
-d "# Simple note
Contenu simple sans front matter."
# Upload depuis un fichier
curl -X PUT http://localhost:8080/api/v1/notes/projet/from-file.md \
-H "Content-Type: text/markdown" \
--data-binary @local-file.md
Supprimer une note
Supprime définitivement une note.
Endpoint : DELETE /api/v1/notes/{path}
Paramètres :
{path}: Chemin relatif de la note (ex:projet/old-note.md)
Réponse : 200 OK
{
"message": "Note deleted successfully",
"path": "projet/old-note.md"
}
Erreurs :
404 Not Found: Note inexistante500 Internal Server Error: Erreur de suppression
Exemple curl :
curl -X DELETE http://localhost:8080/api/v1/notes/projet/old-note.md
Lister les notes publiques
Récupère la liste des notes qui ont été publiées dans l'espace public.
Endpoint : GET /api/public/list
Paramètres : Aucun
Réponse : 200 OK
{
"notes": [
{
"path": "projet/backend.md",
"title": "Backend API",
"published_at": "2025-11-13T14:30:00Z"
},
{
"path": "personal/guide.md",
"title": "Guide d'utilisation",
"published_at": "2025-11-13T10:15:00Z"
}
]
}
Champs retournés :
path: Chemin relatif de la note sourcetitle: Titre de la notepublished_at: Date/heure de publication (format ISO 8601)
Notes :
- Les notes sont triées par date de publication (plus récentes d'abord)
- Les fichiers HTML générés se trouvent dans
public/{nom-de-la-note}.html - Liste vide si aucune note n'est publique
Exemple curl :
# Lister toutes les notes publiques
curl http://localhost:8080/api/public/list
# Avec formatage jq
curl -s http://localhost:8080/api/public/list | jq '.notes[] | "\(.title) -> public/\(.path | split("/")[-1] | sub(".md$"; ".html"))"'
Exemple de sortie formatée :
$ curl -s http://localhost:8080/api/public/list | jq '.notes[] | .title'
"Backend API"
"Guide d'utilisation"
"Documentation projet"
Compter les notes publiques :
curl -s http://localhost:8080/api/public/list | jq '.notes | length'
Basculer le statut public d'une note
Publie ou retire une note de l'espace public. Génère automatiquement un fichier HTML statique exportable.
Endpoint : POST /api/public/toggle
Content-Type : application/x-www-form-urlencoded
Paramètres :
path(form) : Chemin relatif de la note (ex:projet/backend.md)
Réponse : 200 OK
{
"status": "public",
"path": "projet/backend.md"
}
Valeurs possibles pour status :
"public": La note est maintenant publique (HTML généré)"private": La note est maintenant privée (HTML supprimé)
Comportement :
- ✅ Génère du HTML statique dans
public/nom-de-la-note.html - ✅ Copie les CSS nécessaires dans
public/static/ - ✅ Met à jour l'index dans
public/index.html - ✅ Structure plate : Tous les fichiers dans
public/, pas de sous-dossiers - ✅ Portable : Les fichiers HTML peuvent être copiés sur n'importe quel serveur web
Fichiers générés :
public/
├── index.html # Liste de toutes les notes publiques
├── backend.md.html # Note convertie en HTML standalone
├── autre-note.html
└── static/
├── theme.css # Styles copiés
└── themes.css
Erreurs :
400 Bad Request: Chemin manquant ou invalide404 Not Found: Note inexistante405 Method Not Allowed: Méthode autre que POST500 Internal Server Error: Erreur de génération HTML
Exemple curl :
# Publier une note
curl -X POST http://localhost:8080/api/public/toggle \
-d "path=projet/backend.md"
# La note est maintenant accessible à :
# http://localhost:8080/public/backend.html
Exemple JavaScript :
// Publier une note
const response = await fetch('/api/public/toggle', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({ path: 'projet/backend.md' }),
});
const data = await response.json();
console.log(data.status); // "public" ou "private"
Scripts utiles :
#!/bin/bash
# Lister les notes publiques avec leurs URLs
echo "📚 Notes publiques:"
curl -s http://localhost:8080/api/public/list | jq -r '.notes[] | "• \(.title)\n → http://localhost:8080/public/\(.path | split("/")[-1] | sub(".md$"; ".html"))\n"'
#!/bin/bash
# Exporter toutes les notes en HTML public
echo "Exporting all notes to public HTML..."
curl -s http://localhost:8080/api/v1/notes | jq -r '.notes[].path' | while read path; do
curl -X POST http://localhost:8080/api/public/toggle -d "path=$path" > /dev/null 2>&1
echo "✓ Published: $path"
done
echo ""
echo "✅ Export terminé!"
echo "📊 Total: $(curl -s http://localhost:8080/api/public/list | jq '.notes | length') notes publiques"
#!/bin/bash
# Retirer toutes les notes du public
echo "Unpublishing all public notes..."
curl -s http://localhost:8080/api/public/list | jq -r '.notes[].path' | while read path; do
curl -X POST http://localhost:8080/api/public/toggle -d "path=$path" > /dev/null 2>&1
echo "✓ Unpublished: $path"
done
echo "✅ Toutes les notes sont maintenant privées"
Notes publiques
Le système de notes publiques génère des fichiers HTML statiques exportables. Cette section explique comment utiliser ces fichiers.
Accès aux notes publiques
Sur le serveur Personotes :
http://localhost:8080/public/
Fichiers générés :
public/index.html: Liste de toutes les notes publiquespublic/*.html: Notes converties en HTML standalonepublic/static/: CSS et assets
Déploiement
Les fichiers HTML sont complètement autonomes et peuvent être déployés sur :
1. Serveur web classique
# Copier sur un serveur Apache/Nginx
scp -r public/ user@server.com:/var/www/html/notes/
# Ou avec rsync
rsync -av public/ user@server.com:/var/www/html/notes/
Configuration Nginx :
server {
listen 80;
server_name notes.example.com;
root /var/www/html/notes;
index index.html;
}
Configuration Apache :
<VirtualHost *:80>
ServerName notes.example.com
DocumentRoot /var/www/html/notes
</VirtualHost>
2. GitHub Pages (gratuit)
cd public/
git init
git add .
git commit -m "Public notes"
git remote add origin https://github.com/username/notes-public.git
git push -u origin main
# Activer GitHub Pages dans Settings → Pages → main branch
# Vos notes seront accessibles à :
# https://username.github.io/notes-public/
3. Netlify Drop
- Allez sur https://app.netlify.com/drop
- Glissez-déposez le dossier
public/ - Netlify génère automatiquement une URL
4. Vercel
cd public/
npx vercel
Automatisation de l'export
Script de synchronisation :
#!/bin/bash
# sync-public.sh - Synchroniser les notes publiques vers un serveur
REMOTE_USER="user"
REMOTE_HOST="server.com"
REMOTE_PATH="/var/www/html/notes"
rsync -av --delete public/ ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}
echo "✅ Notes publiques synchronisées !"
Git Hook automatique :
# .git/hooks/post-commit
#!/bin/bash
# Si le dossier public/ a changé, synchroniser
if git diff --name-only HEAD~1 | grep -q "^public/"; then
./sync-public.sh
fi
Avantages
- ✅ Performance : HTML pré-généré = chargement instantané
- ✅ Sécurité : Fichiers statiques = surface d'attaque minimale
- ✅ Portabilité : Fonctionne sur n'importe quel serveur web
- ✅ Gratuit : Hébergement possible sur GitHub Pages, Netlify
- ✅ SEO : HTML pré-rendu = indexation optimale par Google
- ✅ Pas de backend : Pas besoin de Go sur le serveur de destination
Limitations
- ⚠️ Noms uniques : Si deux notes dans différents dossiers ont le même nom (ex:
personal/test.mdetwork/test.md), elles s'écraseront car la structure est plate - ⚠️ Republication manuelle : Si vous modifiez une note déjà publique, vous devez la republier pour régénérer le HTML
- ⚠️ Pas de recherche : Les fichiers HTML n'incluent pas de fonction de recherche (uniquement consultables)
Documentation complète
Pour plus d'informations sur l'export des notes publiques :
- QUICK_START_PUBLIC.md : Guide de démarrage rapide
- EXPORT_GUIDE.md : Guide complet de déploiement
Codes de statut HTTP
| Code | Signification | Description |
|---|---|---|
200 |
OK | Requête réussie |
201 |
Created | Note créée avec succès |
400 |
Bad Request | Requête invalide (chemin, JSON, etc.) |
404 |
Not Found | Note inexistante |
405 |
Method Not Allowed | Méthode HTTP non supportée |
415 |
Unsupported Media Type | Content-Type non supporté |
500 |
Internal Server Error | Erreur serveur |
Exemples d'utilisation
Synchronisation de notes
Télécharger toutes les notes :
#!/bin/bash
# Télécharger toutes les notes localement
mkdir -p notes-backup
# Récupérer la liste
curl -s http://localhost:8080/api/v1/notes | jq -r '.notes[].path' | while read path; do
# Créer les dossiers parents
mkdir -p "notes-backup/$(dirname "$path")"
# Télécharger la note
curl -s http://localhost:8080/api/v1/notes/"$path" \
-H "Accept: text/markdown" \
-o "notes-backup/$path"
echo "✓ Downloaded: $path"
done
echo "Backup terminé!"
Uploader un dossier de notes :
#!/bin/bash
# Uploader toutes les notes .md d'un dossier
find ./my-notes -name "*.md" | while read file; do
# Calculer le chemin relatif
relpath="${file#./my-notes/}"
# Upload
curl -X PUT http://localhost:8080/api/v1/notes/"$relpath" \
-H "Content-Type: text/markdown" \
--data-binary @"$file"
echo "✓ Uploaded: $relpath"
done
echo "Upload terminé!"
Recherche et filtrage
Lister toutes les notes avec un tag spécifique :
curl -s http://localhost:8080/api/v1/notes | \
jq '.notes[] | select(.tags | contains(["projet"])) | .path'
Compter les notes par dossier :
curl -s http://localhost:8080/api/v1/notes | \
jq -r '.notes[].path' | \
xargs -n1 dirname | \
sort | uniq -c
Création automatique de notes
Note quotidienne :
#!/bin/bash
# Créer une note quotidienne
TODAY=$(date +%Y-%m-%d)
TITLE="Notes du $(date +%d/%m/%Y)"
curl -X PUT http://localhost:8080/api/v1/notes/daily/${TODAY}.md \
-H "Content-Type: application/json" \
-d "{
\"body\": \"\\n# ${TITLE}\\n\\n## Tasks\\n- [ ] TODO\\n\\n## Notes\\n\",
\"frontMatter\": {
\"title\": \"${TITLE}\",
\"tags\": [\"daily\"]
}
}"
echo "Note quotidienne créée: daily/${TODAY}.md"
Intégration avec d'autres outils
Exporter en HTML avec Pandoc :
curl -s http://localhost:8080/api/v1/notes/projet/doc.md \
-H "Accept: text/markdown" | \
pandoc -f markdown -t html -o doc.html
echo "Exporté en HTML: doc.html"
Recherche full-text avec jq :
# Chercher "API" dans tous les titres
curl -s http://localhost:8080/api/v1/notes | \
jq '.notes[] | select(.title | contains("API"))'
Script de maintenance
Vérifier les notes sans tags :
curl -s http://localhost:8080/api/v1/notes | \
jq -r '.notes[] | select(.tags | length == 0) | .path'
Statistiques :
#!/bin/bash
# Afficher des statistiques sur les notes
STATS=$(curl -s http://localhost:8080/api/v1/notes)
TOTAL=$(echo "$STATS" | jq '.total')
TOTAL_SIZE=$(echo "$STATS" | jq '[.notes[].size] | add')
AVG_SIZE=$(echo "$STATS" | jq '[.notes[].size] | add / length | floor')
echo "📊 Statistiques des notes"
echo "========================"
echo "Total de notes: $TOTAL"
echo "Taille totale: $(numfmt --to=iec-i --suffix=B $TOTAL_SIZE)"
echo "Taille moyenne: $(numfmt --to=iec-i --suffix=B $AVG_SIZE)"
echo ""
echo "Top 5 tags:"
echo "$STATS" | jq -r '.notes[].tags[]' | sort | uniq -c | sort -rn | head -5
Bonnes pratiques
Sécurité
- Ne pas exposer publiquement sans authentification
- Utiliser HTTPS en production
- Valider les chemins côté client (éviter
../malveillants) - Limiter la taille des uploads (si nécessaire, ajouter un middleware)
Performance
- Pagination : L'API liste ne pagine pas actuellement (toutes les notes en une requête). Pour beaucoup de notes (>1000), envisager d'ajouter
?limit=et?offset= - Cache : Utiliser un proxy cache (Varnish, nginx) pour GET
- Compression : Activer gzip sur le reverse proxy
Workflow recommandé
- Backup régulier : Script cron qui télécharge toutes les notes
- Versioning Git : Synchroniser le dossier de notes avec Git
- CI/CD : Valider le format Markdown avec des linters
- Monitoring : Logger les accès API pour audit
Support et contribution
- Issues : Rapporter les bugs sur GitHub
- Documentation : Ce fichier (
API.md) - Code source :
internal/api/rest_handler.go
Changelog
v1 (2025-11-13)
- ✨ Première version de l'API REST
- ✅ Endpoints: LIST, GET, PUT, DELETE
- ✅ Content negotiation JSON/Markdown
- ✅ Support sous-dossiers
- ✅ Gestion automatique du front matter
- ✅ Ré-indexation automatique
- ✅ Export de notes publiques en HTML statique (POST /api/public/toggle)
Note : Cette API coexiste avec l'interface web HTML. Les deux peuvent être utilisées simultanément sans conflit.