Skip to content

Commit 85569ff

Browse files
committed
Add products reset endpoint and update routes
Bump version to 1.0.9, remove legacy echo and CSV import endpoints, and add a new /products/reset endpoint that recreates and seeds the product table. Exports reset router from app.api.products and includes it in the central routes; also keep the products listing route that returns product data with enriched meta (version, base_url, timestamp). Update app metadata/title in main.py and adjust tests to validate the new meta structure.
1 parent 1dbab98 commit 85569ff

9 files changed

Lines changed: 111 additions & 75 deletions

File tree

app/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""NX AI - FastAPI/Python/Postgres/tsvector"""
22

33
# Current Version
4-
__version__ = "1.0.8"
4+
__version__ = "1.0.9"

app/api/echo.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

app/api/import_csv.py

Lines changed: 0 additions & 56 deletions
This file was deleted.

app/api/products/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
from .products import router
2+
from .reset import router as reset_router

app/api/products/products.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from app import __version__
22
from fastapi import APIRouter
3+
from fastapi import status
34
import os, time
45
import psycopg2
56
from dotenv import load_dotenv

app/api/products/reset.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import os
2+
import psycopg2
3+
from dotenv import load_dotenv
4+
from fastapi import APIRouter, status
5+
6+
router = APIRouter()
7+
8+
@router.post("/products/reset", status_code=status.HTTP_200_OK)
9+
def reset_products() -> dict:
10+
"""Delete and recreate the product table, then seed with initial data."""
11+
load_dotenv()
12+
conn = psycopg2.connect(
13+
host=os.getenv('DB_HOST'),
14+
port=os.getenv('DB_PORT', '5432'),
15+
dbname=os.getenv('DB_NAME'),
16+
user=os.getenv('DB_USER'),
17+
password=os.getenv('DB_PASSWORD')
18+
)
19+
cur = conn.cursor()
20+
# Drop and recreate table
21+
cur.execute('''
22+
DROP TABLE IF EXISTS product;
23+
CREATE TABLE product (
24+
id SERIAL PRIMARY KEY,
25+
name VARCHAR(255) NOT NULL,
26+
description TEXT,
27+
price NUMERIC(10,2) NOT NULL,
28+
in_stock BOOLEAN DEFAULT TRUE,
29+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
30+
);
31+
''')
32+
# Seed data
33+
seed_products = [
34+
("Apple", "Fresh red apple", 0.99, True),
35+
("Banana", "Organic banana", 0.59, True),
36+
("Orange", "Juicy orange", 1.29, True),
37+
]
38+
cur.executemany(
39+
"INSERT INTO product (name, description, price, in_stock) VALUES (%s, %s, %s, %s);",
40+
seed_products
41+
)
42+
conn.commit()
43+
cur.execute('SELECT id, name, description, price, in_stock, created_at FROM product;')
44+
products = [
45+
{
46+
"id": row[0],
47+
"name": row[1],
48+
"description": row[2],
49+
"price": float(row[3]),
50+
"in_stock": row[4],
51+
"created_at": row[5].isoformat() if row[5] else None
52+
}
53+
for row in cur.fetchall()
54+
]
55+
cur.close()
56+
conn.close()
57+
return {"message": "Product table reset and seeded.", "data": products}
58+
import os, time
59+
import psycopg2
60+
from dotenv import load_dotenv
61+
from app import __version__
62+
63+
router = APIRouter()
64+
65+
@router.get("/products")
66+
def root() -> dict:
67+
"""Return a structured welcome message for the API root, including product data."""
68+
load_dotenv()
69+
conn = psycopg2.connect(
70+
host=os.getenv('DB_HOST'),
71+
port=os.getenv('DB_PORT', '5432'),
72+
dbname=os.getenv('DB_NAME'),
73+
user=os.getenv('DB_USER'),
74+
password=os.getenv('DB_PASSWORD')
75+
)
76+
cur = conn.cursor()
77+
cur.execute('SELECT id, name, description, price, in_stock, created_at FROM product;')
78+
products = [
79+
{
80+
"id": row[0],
81+
"name": row[1],
82+
"description": row[2],
83+
"price": float(row[3]),
84+
"in_stock": row[4],
85+
"created_at": row[5].isoformat() if row[5] else None
86+
}
87+
for row in cur.fetchall()
88+
]
89+
cur.close()
90+
conn.close()
91+
92+
load_dotenv()
93+
base_url = os.getenv("BASE_URL", "http://localhost:8000")
94+
95+
epoch = int(time.time() * 1000)
96+
meta = {
97+
"severity": "success",
98+
"title": "Product List",
99+
"version": __version__,
100+
"base_url": base_url,
101+
"time": epoch,
102+
}
103+
return {"meta": meta, "data": products}

app/api/routes.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@
1212

1313
from app.api.root import router as root_router
1414
from app.api.health import router as health_router
15-
from app.api.echo import router as echo_router
16-
from app.api.import_csv import router as import_csv_router
1715
from app.api.products.products import router as products_router
16+
from app.api.products.reset import router as reset_router
1817

1918
router.include_router(root_router)
2019
router.include_router(health_router)
21-
router.include_router(echo_router)
22-
router.include_router(import_csv_router)
2320
router.include_router(products_router)
21+
router.include_router(reset_router)

app/main.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from app import __version__
2-
"""NX AI - FastAPI entry point."""
3-
2+
"""NX-AI Open Source, production ready Python FastAPI/Postgres app for NX"""
43

54
from fastapi import FastAPI
65
from fastapi.middleware.cors import CORSMiddleware
@@ -12,7 +11,7 @@
1211
from app.api.routes import router
1312

1413
app = FastAPI(
15-
title="NX AI",
14+
title="NX-AI",
1615
description="Production-ready Python FastAPI app for NX",
1716
version=__version__,
1817
)

tests/test_routes.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ def test_root_returns_welcome_message() -> None:
1717
json_data = response.json()
1818
assert "meta" in json_data
1919
assert "data" in json_data
20-
assert "message" in json_data["meta"]
21-
assert "NX AI" in json_data["meta"]["message"]
22-
20+
assert "title" in json_data["meta"]
2321

2422
def test_health_returns_ok() -> None:
2523
"""GET /health should return status ok."""

0 commit comments

Comments
 (0)