Skip to main content

Un convertisseur JSON ↔ JSON++ optimisé

Project description

JSON++ (JONX) - Format de fichier optimisé pour JSON

JSON++ (JONX) est un format de fichier binaire optimisé pour stocker des données JSON de manière efficace. Il utilise la compression zstd et le stockage en colonnes pour réduire la taille des fichiers et améliorer les performances de lecture.

📋 Table des matières

🚀 Installation

Dépendances

pip install -r requirements.txt

Les dépendances requises sont :

  • fastapi>=0.104.0 - Framework web pour l'API
  • uvicorn[standard]>=0.24.0 - Serveur ASGI
  • orjson>=3.9.0 - Parser JSON rapide
  • zstandard>=0.21.0 - Compression zstd
  • python-multipart>=0.0.6 - Gestion des uploads de fichiers

🏗️ Architecture

Le projet est composé de trois modules principaux :

encoder.py

Module d'encodage qui convertit des fichiers JSON en format JONX.

Fonctions principales :

  • detect_type(values) : Détecte automatiquement le type d'une colonne (int32, float32, str, bool, json)
  • pack_column(values, col_type) : Transforme une colonne en format binaire ou JSON compressé
  • jonx_encode(json_path, jonx_path) : Fonction principale pour encoder un fichier JSON en JONX

Caractéristiques :

  • Détection automatique des colonnes et types
  • Compression zstd (niveau 3)
  • Création automatique d'index pour les colonnes numériques
  • Stockage en colonnes pour une meilleure compression

decoder.py

Module de décodage qui lit et décompresse les fichiers JONX.

Classe principale :

  • JONXFile : Classe pour charger et manipuler les fichiers JONX

Méthodes :

  • __init__(path) : Charge un fichier JONX
  • get_column(field_name) : Récupère une colonne décompressée
  • find_min(field_name, use_index=False) : Trouve la valeur minimale d'une colonne (avec support d'index)

Caractéristiques :

  • Chargement paresseux (colonnes compressées stockées en mémoire)
  • Décompression à la demande
  • Support des index pour recherches rapides

server.py

Serveur FastAPI qui expose une API REST complète pour convertir entre JSON et JONX.

Endpoints disponibles :

  • GET / : Redirection vers la documentation Swagger (/docs)
  • GET /health : Vérification de santé de l'API
  • POST /api/encode : Encoder un fichier JSON → JONX (upload fichier)
  • POST /api/encode/json : Encoder JSON → JONX (body JSON)
  • POST /api/decode : Décoder un fichier JONX → JSON
  • POST /api/preview : Prévisualiser les métadonnées JONX sans générer le fichier

Fonctionnalités :

  • API REST complète avec documentation interactive (Swagger UI et ReDoc)
  • Conversion bidirectionnelle JSON ↔ JONX
  • Détection automatique des types de colonnes
  • Compression zstd optimisée
  • Index automatiques pour colonnes numériques
  • Prévisualisation des métadonnées
  • Gestion CORS pour les requêtes cross-origin
  • Gestion d'erreurs complète avec codes HTTP appropriés

📦 Format JONX|JSON++

Le format JONX est structuré comme suit :

[Header: 8 bytes]
├── Signature: "JONX" (4 bytes)
└── Version: uint32 (4 bytes)

[Schéma compressé]
├── Taille: uint32 (4 bytes)
└── Données compressées (zstd)

[Colonnes compressées]
├── Pour chaque colonne:
│   ├── Taille: uint32 (4 bytes)
│   └── Données compressées (zstd)

[Index compressés]
├── Nombre d'index: uint32 (4 bytes)
└── Pour chaque index:
    ├── Taille du nom: uint32 (4 bytes)
    ├── Nom du champ (UTF-8)
    ├── Taille de l'index: uint32 (4 bytes)
    └── Index compressé (zstd)

Types de données supportés

  • int32 : Entiers 32 bits (stockés en binaire)
  • float32 : Flottants 32 bits (stockés en binaire)
  • bool : Booléens (stockés en binaire)
  • str : Chaînes de caractères (JSON compressé)
  • json : Objets complexes (JSON compressé)

Index automatiques

Les colonnes numériques (int32, float32) génèrent automatiquement un index trié pour permettre des recherches rapides (min, max, etc.).

💻 Utilisation

encoder.py

from backend.logical.encoder import jonx_encode

# Convertir un fichier JSON en JONX
jonx_encode("data/json/data.json", "data/json++/data_jonx.json++")

Exemple de JSON d'entrée :

[
  {"id": 1, "name": "Produit 1", "price": 100, "category": "Électronique"},
  {"id": 2, "name": "Produit 2", "price": 200, "category": "Vêtements"}
]

Résultat :

  • Fichier data_jonx.json++ créé avec compression zstd
  • Index automatique sur les colonnes id et price

decoder.py

from backend.logical.decoder import JONXFile

# Charger un fichier JONX
jonx_file = JONXFile("json++/data_jonx.json++")

# Accéder à une colonne
prices = jonx_file.get_column("price")

# Trouver le prix minimum (avec index pour performance)
min_price = jonx_file.find_min("price", use_index=True)
print(f"Prix minimum: {min_price}")

# Reconstruire le JSON complet
columns = {}
for field in jonx_file.fields:
    columns[field] = jonx_file.get_column(field)

# Reconstruire les objets
num_rows = len(columns[jonx_file.fields[0]])
json_data = []
for i in range(num_rows):
    obj = {field: columns[field][i] for field in jonx_file.fields}
    json_data.append(obj)

Méthodes disponibles :

  • get_column(field_name) : Récupère une colonne décompressée
  • find_min(field_name, use_index=False) : Trouve la valeur minimale
  • Propriétés : fields, types, indexes

server.py

Démarrage du serveur

# Méthode 1 : Directement avec Python
python server.py

# Méthode 2 : Avec uvicorn
uvicorn server:app --reload --host 0.0.0.0 --port 8000

Le serveur démarre sur http://localhost:8000

Documentation interactive

Accédez à http://localhost:8000/docs pour utiliser l'interface Swagger UI qui permet :

  • Tester tous les endpoints directement depuis le navigateur
  • Voir la documentation complète de chaque endpoint
  • Exécuter des requêtes avec des exemples pré-remplis
  • Voir les schémas de requête/réponse en détail

Accédez à http://localhost:8000/redoc pour une documentation alternative en format ReDoc.

🔌 API REST

L'API REST expose plusieurs endpoints pour convertir entre JSON et JONX. La documentation interactive est disponible sur /docs (Swagger UI) et /redoc (ReDoc).

GET /health

Vérification de santé de l'API

Endpoint de santé pour vérifier que l'API est opérationnelle. Utile pour les systèmes de monitoring et les health checks.

Méthode : GET

Réponse :

{
  "status": "healthy",
  "service": "JONX API",
  "version": "1.0.0"
}

Exemple avec curl :

curl http://localhost:8000/health

Exemple avec Python :

import requests
response = requests.get("http://localhost:8000/health")
print(response.json())

POST /api/encode

Encoder JSON → JONX (upload fichier)

Encode un fichier JSON en format JONX optimisé via upload de fichier.

Méthode : POST

Content-Type : multipart/form-data

Paramètres :

  • file (requis) : Fichier JSON à encoder (doit être une liste d'objets)

Format d'entrée :

  • Le fichier JSON doit être une liste d'objets (array)
  • Tous les objets doivent avoir les mêmes clés
  • Les types sont détectés automatiquement

Réponse :

  • Type : application/octet-stream
  • Headers : Content-Disposition: attachment; filename="<nom>.json++"
  • Corps : Fichier binaire JONX téléchargeable

Codes d'erreur :

  • 400 : Aucun fichier fourni, JSON invalide, ou liste vide
  • 500 : Erreur interne lors de l'encodage

Exemple avec curl :

curl -X POST "http://localhost:8000/api/encode" \
     -F "file=@data.json" \
     --output output.json++

Exemple avec Python :

import requests

with open("data.json", "rb") as f:
    response = requests.post(
        "http://localhost:8000/api/encode",
        files={"file": f}
    )

with open("output.json++", "wb") as out:
    out.write(response.content)

Format JSON d'entrée attendu :

[
  {"id": 1, "name": "Produit 1", "price": 100.50, "active": true},
  {"id": 2, "name": "Produit 2", "price": 200.75, "active": false}
]

POST /api/encode/json

Encoder JSON → JONX (body JSON)

Encode des données JSON envoyées dans le body de la requête en format JONX. Alternative à l'upload de fichier pour les données générées dynamiquement.

Méthode : POST

Content-Type : application/json

Body :

{
  "data": [
    {"id": 1, "name": "Produit 1", "price": 100.50},
    {"id": 2, "name": "Produit 2", "price": 200.75}
  ]
}

Réponse :

  • Type : application/octet-stream
  • Headers : Content-Disposition: attachment; filename="output.json++"
  • Corps : Fichier binaire JONX téléchargeable

Codes d'erreur :

  • 400 : JSON invalide ou liste vide
  • 500 : Erreur interne lors de l'encodage

Exemple avec curl :

curl -X POST "http://localhost:8000/api/encode/json" \
     -H "Content-Type: application/json" \
     -d '{
       "data": [
         {"id": 1, "name": "Produit 1", "price": 100.50},
         {"id": 2, "name": "Produit 2", "price": 200.75}
       ]
     }' \
     --output output.json++

Exemple avec Python :

import requests

data = {
    "data": [
        {"id": 1, "name": "Produit 1", "price": 100.50, "active": True},
        {"id": 2, "name": "Produit 2", "price": 200.75, "active": False}
    ]
}

response = requests.post(
    "http://localhost:8000/api/encode/json",
    json=data
)

with open("output.json++", "wb") as f:
    f.write(response.content)

POST /api/decode

Décoder JONX → JSON

Décode un fichier JONX et retourne les données JSON reconstruites avec toutes les métadonnées.

Méthode : POST

Content-Type : multipart/form-data

Paramètres :

  • file (requis) : Fichier JONX à décoder (extension .json++ ou .jonx)

Réponse :

{
  "success": true,
  "file_name": "data.json++",
  "file_size": 273,
  "version": 1,
  "fields": ["id", "name", "price", "active"],
  "types": {
    "id": "int32",
    "name": "str",
    "price": "float32",
    "active": "bool"
  },
  "num_rows": 2,
  "json_data": [
    {"id": 1, "name": "Produit 1", "price": 100.50, "active": true},
    {"id": 2, "name": "Produit 2", "price": 200.75, "active": false}
  ]
}

Champs de la réponse :

  • success : Indicateur de succès (bool)
  • file_name : Nom du fichier uploadé (str)
  • file_size : Taille du fichier en bytes (int)
  • version : Version du format JONX (int)
  • fields : Liste des noms de colonnes (list)
  • types : Dictionnaire des types par colonne (dict)
  • num_rows : Nombre de lignes de données (int)
  • json_data : Données JSON reconstruites (list)

Codes d'erreur :

  • 400 : Aucun fichier fourni ou fichier JONX invalide
  • 500 : Erreur interne lors du décodage

Exemple avec curl :

curl -X POST "http://localhost:8000/api/decode" \
     -F "file=@data.json++"

Exemple avec Python :

import requests
import json

with open("data.json++", "rb") as f:
    response = requests.post(
        "http://localhost:8000/api/decode",
        files={"file": f}
    )

result = response.json()
print(f"Colonnes: {result['fields']}")
print(f"Types: {result['types']}")
print(f"Nombre de lignes: {result['num_rows']}")
print(f"Données: {json.dumps(result['json_data'], indent=2)}")

POST /api/preview

Prévisualiser les métadonnées JONX

Prévisualise les métadonnées et estime la taille d'un fichier JONX sans le générer. Utile pour valider la structure des données avant l'encodage.

Méthode : POST

Content-Type : application/json

Body :

{
  "data": [
    {"id": 1, "name": "Produit 1", "price": 100.50, "active": true},
    {"id": 2, "name": "Produit 2", "price": 200.75, "active": false}
  ]
}

Réponse :

{
  "success": true,
  "version": 1,
  "fields": ["id", "name", "price", "active"],
  "types": {
    "id": "int32",
    "name": "str",
    "price": "float32",
    "active": "bool"
  },
  "num_rows": 2,
  "estimated_size": 273
}

Champs de la réponse :

  • success : Indicateur de succès (bool)
  • version : Version du format JONX qui serait utilisée (int)
  • fields : Liste des colonnes détectées (list)
  • types : Types automatiquement détectés pour chaque colonne (dict)
  • num_rows : Nombre de lignes de données (int)
  • estimated_size : Taille estimée du fichier JONX en bytes (int)

Détection automatique des types :

  • int32 : Entiers
  • float32 : Nombres décimaux
  • str : Chaînes de caractères
  • bool : Booléens
  • json : Objets complexes (fallback)

Codes d'erreur :

  • 400 : Liste JSON vide
  • 500 : Erreur interne lors de l'analyse

Exemple avec curl :

curl -X POST "http://localhost:8000/api/preview" \
     -H "Content-Type: application/json" \
     -d '{
       "data": [
         {"id": 1, "name": "Produit 1", "price": 100.50, "active": true},
         {"id": 2, "name": "Produit 2", "price": 200.75, "active": false}
       ]
     }'

Exemple avec Python :

import requests

data = {
    "data": [
        {"id": 1, "name": "Produit 1", "price": 100.50, "active": True},
        {"id": 2, "name": "Produit 2", "price": 200.75, "active": False}
    ]
}

response = requests.post(
    "http://localhost:8000/api/preview",
    json=data
)

result = response.json()
print(f"Colonnes détectées: {result['fields']}")
print(f"Types: {result['types']}")
print(f"Taille estimée: {result['estimated_size']} bytes")

📝 Exemples

Exemple complet : Encoder puis décoder

from backend.logical.encoder import jonx_encode
from backend.logical.decoder import JONXFile

# 1. Encoder un JSON en JONX
jonx_encode("data/json/data.json", "data/json++/data_jonx.json++")

# 2. Charger le fichier JONX
jonx_file = JONXFile("data/json++/data_jonx.json++")

# 3. Accéder aux métadonnées
print(f"Colonnes: {jonx_file.fields}")
print(f"Types: {jonx_file.types}")

# 4. Récupérer une colonne spécifique
prices = jonx_file.get_column("price")
print(f"Prix: {prices}")

# 5. Utiliser les index pour des recherches rapides
min_price = jonx_file.find_min("price", use_index=True)
print(f"Prix minimum: {min_price}")

Exemple complet avec l'API REST

import requests
import json

# 1. Prévisualiser les métadonnées
preview_data = {
    "data": [
        {"id": 1, "name": "Produit 1", "price": 100.50, "active": True},
        {"id": 2, "name": "Produit 2", "price": 200.75, "active": False}
    ]
}

response = requests.post(
    "http://localhost:8000/api/preview",
    json=preview_data
)
preview_result = response.json()
print(f"Métadonnées: {json.dumps(preview_result, indent=2)}")

# 2. Encoder JSON → JONX (via body JSON)
response = requests.post(
    "http://localhost:8000/api/encode/json",
    json=preview_data
)

with open("output.json++", "wb") as f:
    f.write(response.content)
print("Fichier JONX créé: output.json++")

# 3. Décoder JONX → JSON
with open("output.json++", "rb") as f:
    response = requests.post(
        "http://localhost:8000/api/decode",
        files={"file": f}
    )
    decode_result = response.json()
    print(f"Données décodées: {json.dumps(decode_result['json_data'], indent=2)}")

# 4. Encoder depuis un fichier JSON
with open("data.json", "rb") as f:
    response = requests.post(
        "http://localhost:8000/api/encode",
        files={"file": f}
    )
    with open("data.json++", "wb") as out:
        out.write(response.content)
    print("Fichier JONX créé depuis upload: data.json++")

# 5. Vérifier la santé de l'API
response = requests.get("http://localhost:8000/health")
print(f"Statut API: {response.json()}")

🎯 Avantages du format JONX

  1. Compression efficace : Utilisation de zstd pour une compression optimale
  2. Stockage en colonnes : Meilleure compression pour les données tabulaires
  3. Types optimisés : Stockage binaire pour les types numériques
  4. Index automatiques : Recherches rapides sur les colonnes numériques
  5. Lecture sélective : Décompression à la demande des colonnes
  6. Format binaire : Plus rapide à lire que JSON textuel

Licence

Ce projet est fourni tel quel pour usage éducatif et de développement.

Contribution

Les contributions sont les bienvenues ! N'hésitez pas à ouvrir une issue ou une pull request.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jsonplusplus-1.0.0.tar.gz (13.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jsonplusplus-1.0.0-py3-none-any.whl (9.6 kB view details)

Uploaded Python 3

File details

Details for the file jsonplusplus-1.0.0.tar.gz.

File metadata

  • Download URL: jsonplusplus-1.0.0.tar.gz
  • Upload date:
  • Size: 13.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for jsonplusplus-1.0.0.tar.gz
Algorithm Hash digest
SHA256 e3a25597f073c365b95393dbf042858c21c6aa236eb8fb0638036ac9118862dd
MD5 f1b473b45c26fdca879f0b83b2220313
BLAKE2b-256 b4f2a519680c65f84d9819e3eb9fc9094c0b9c78e1d46dea6fb79eedbb8798ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonplusplus-1.0.0.tar.gz:

Publisher: workflow.yml on Nathan-Josue/jsonplusplus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonplusplus-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: jsonplusplus-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 9.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for jsonplusplus-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b08de0961df691126c7499eaf15c5e366d3885622e4979fb58755a7f53f70652
MD5 66571bc3f4051ec0998272a36c46b8a7
BLAKE2b-256 ccaffc4c9e9efa754d2bd7ad6d899fb637d84b5466cbb26d8a4e64ef2abf57db

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonplusplus-1.0.0-py3-none-any.whl:

Publisher: workflow.yml on Nathan-Josue/jsonplusplus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page