Files
personotes/API.md

22 KiB

PersoNotes REST API Documentation

Version: v1 Base URL: http://localhost:8080/api/v1

Table des matières


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/v1 pour 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.json n'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 :

  1. Utilisez un reverse proxy (nginx, Caddy) avec authentification
  2. Implémentez Basic Auth ou API Key
  3. 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ées
  • Accept: text/markdown : Retourne Markdown brut
  • Accept: 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 JSON
  • Content-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_modified automatiquement
  • Préserve date pour 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 inexistante
  • 500 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 source
  • title : Titre de la note
  • published_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 invalide
  • 404 Not Found : Note inexistante
  • 405 Method Not Allowed : Méthode autre que POST
  • 500 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 publiques
  • public/*.html : Notes converties en HTML standalone
  • public/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

  1. Allez sur https://app.netlify.com/drop
  2. Glissez-déposez le dossier public/
  3. 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.md et work/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é

  1. Ne pas exposer publiquement sans authentification
  2. Utiliser HTTPS en production
  3. Valider les chemins côté client (éviter ../ malveillants)
  4. Limiter la taille des uploads (si nécessaire, ajouter un middleware)

Performance

  1. 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=
  2. Cache : Utiliser un proxy cache (Varnish, nginx) pour GET
  3. Compression : Activer gzip sur le reverse proxy

Workflow recommandé

  1. Backup régulier : Script cron qui télécharge toutes les notes
  2. Versioning Git : Synchroniser le dossier de notes avec Git
  3. CI/CD : Valider le format Markdown avec des linters
  4. 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.