API: endpoint /schema (#78)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
from flask_smorest import Blueprint
|
from flask_smorest import Blueprint
|
||||||
|
|
||||||
|
from src.api.auth import require_token
|
||||||
|
from src.db import schema as duckdb_schema
|
||||||
|
|
||||||
bp = Blueprint(
|
bp = Blueprint(
|
||||||
"api_v1",
|
"api_v1",
|
||||||
"api_v1",
|
"api_v1",
|
||||||
@@ -12,3 +15,11 @@ bp = Blueprint(
|
|||||||
def health():
|
def health():
|
||||||
"""Sonde de santé, sans authentification."""
|
"""Sonde de santé, sans authentification."""
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/schema")
|
||||||
|
@require_token
|
||||||
|
def schema():
|
||||||
|
"""Liste des colonnes disponibles dans le dataset DECP."""
|
||||||
|
cols = [{"name": name, "type": str(dtype)} for name, dtype in duckdb_schema.items()]
|
||||||
|
return {"columns": cols}
|
||||||
|
|||||||
@@ -10,3 +10,27 @@ def temp_db(tmp_path, monkeypatch):
|
|||||||
|
|
||||||
tokens_db.init_schema(db_path)
|
tokens_db.init_schema(db_path)
|
||||||
return db_path
|
return db_path
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def api_client(monkeypatch, tmp_path):
|
||||||
|
"""Client Flask test avec USERS_DB_PATH éphémère et blueprint API monté."""
|
||||||
|
db_path = tmp_path / "users.test.sqlite"
|
||||||
|
monkeypatch.setenv("USERS_DB_PATH", str(db_path))
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
from src.api import init_api, tokens_db
|
||||||
|
|
||||||
|
tokens_db.init_schema(db_path)
|
||||||
|
server = Flask(__name__)
|
||||||
|
init_api(server)
|
||||||
|
return server.test_client(), db_path
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def valid_token_header(api_client):
|
||||||
|
from src.api import tokens_db
|
||||||
|
|
||||||
|
_, db_path = api_client
|
||||||
|
token, _ = tokens_db.create_token(db_path, "test-token")
|
||||||
|
return {"Authorization": f"Bearer {token}"}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
def test_schema_without_token_returns_401(api_client):
|
||||||
|
client, _ = api_client
|
||||||
|
resp = client.get("/api/v1/schema")
|
||||||
|
assert resp.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_returns_columns(api_client, valid_token_header):
|
||||||
|
client, _ = api_client
|
||||||
|
resp = client.get("/api/v1/schema", headers=valid_token_header)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.get_json()
|
||||||
|
assert "columns" in data
|
||||||
|
assert isinstance(data["columns"], list)
|
||||||
|
assert len(data["columns"]) > 0
|
||||||
|
first = data["columns"][0]
|
||||||
|
assert set(first.keys()) >= {"name", "type"}
|
||||||
|
# uid doit être présent dans le schéma DECP de test
|
||||||
|
names = [c["name"] for c in data["columns"]]
|
||||||
|
assert "uid" in names
|
||||||
Reference in New Issue
Block a user