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'APIuvicorn[standard]>=0.24.0- Serveur ASGIorjson>=3.9.0- Parser JSON rapidezstandard>=0.21.0- Compression zstdpython-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 JONXget_column(field_name): Récupère une colonne décompresséefind_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'APIPOST /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 → JSONPOST /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
idetprice
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éefind_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 vide500: 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 vide500: 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 invalide500: 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: Entiersfloat32: Nombres décimauxstr: Chaînes de caractèresbool: Booléensjson: Objets complexes (fallback)
Codes d'erreur :
400: Liste JSON vide500: 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
- Compression efficace : Utilisation de zstd pour une compression optimale
- Stockage en colonnes : Meilleure compression pour les données tabulaires
- Types optimisés : Stockage binaire pour les types numériques
- Index automatiques : Recherches rapides sur les colonnes numériques
- Lecture sélective : Décompression à la demande des colonnes
- 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3a25597f073c365b95393dbf042858c21c6aa236eb8fb0638036ac9118862dd
|
|
| MD5 |
f1b473b45c26fdca879f0b83b2220313
|
|
| BLAKE2b-256 |
b4f2a519680c65f84d9819e3eb9fc9094c0b9c78e1d46dea6fb79eedbb8798ac
|
Provenance
The following attestation bundles were made for jsonplusplus-1.0.0.tar.gz:
Publisher:
workflow.yml on Nathan-Josue/jsonplusplus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jsonplusplus-1.0.0.tar.gz -
Subject digest:
e3a25597f073c365b95393dbf042858c21c6aa236eb8fb0638036ac9118862dd - Sigstore transparency entry: 722552710
- Sigstore integration time:
-
Permalink:
Nathan-Josue/jsonplusplus@8ec1f12e71e1ad352f1ca56638fcdd7327a97252 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/Nathan-Josue
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@8ec1f12e71e1ad352f1ca56638fcdd7327a97252 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b08de0961df691126c7499eaf15c5e366d3885622e4979fb58755a7f53f70652
|
|
| MD5 |
66571bc3f4051ec0998272a36c46b8a7
|
|
| BLAKE2b-256 |
ccaffc4c9e9efa754d2bd7ad6d899fb637d84b5466cbb26d8a4e64ef2abf57db
|
Provenance
The following attestation bundles were made for jsonplusplus-1.0.0-py3-none-any.whl:
Publisher:
workflow.yml on Nathan-Josue/jsonplusplus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jsonplusplus-1.0.0-py3-none-any.whl -
Subject digest:
b08de0961df691126c7499eaf15c5e366d3885622e4979fb58755a7f53f70652 - Sigstore transparency entry: 722552788
- Sigstore integration time:
-
Permalink:
Nathan-Josue/jsonplusplus@8ec1f12e71e1ad352f1ca56638fcdd7327a97252 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/Nathan-Josue
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@8ec1f12e71e1ad352f1ca56638fcdd7327a97252 -
Trigger Event:
release
-
Statement type: