From ade138ae05c98196a977eb9f1a2447660e98b070 Mon Sep 17 00:00:00 2001 From: CaffeineFueled Date: Tue, 24 Jun 2025 00:55:40 +0200 Subject: [PATCH] ADD feature to allow donwload of source file with src endpoint --- README.md | 35 +++++++++++++++++++++++++++++------ main.py | 17 ++++++++++++++--- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4b50be8..4563e12 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ A simple FastAPI application that automatically exposes CSV and JSON files as API endpoints. +# TODO +- [x] show source format as well +- [ ] allow upload of static files (with password) + ## Features - Automatically creates API endpoints for CSV and JSON files in the `source` directory @@ -40,11 +44,14 @@ The API will be available at: http://localhost:8000 ## API Endpoints - `GET /` - Welcome message -- `GET /api/{filename}` - Access data from files in the source directory +- `GET /api/{filename}` - Access parsed data from files in the source directory +- `GET /api/{filename}/src` - Download the original source file Example: -- `GET /api/contacts` - Returns data from `source/contacts.csv` -- `GET /api/users` - Returns data from `source/users.json` +- `GET /api/contacts` - Returns parsed data from `source/contacts.csv` as JSON +- `GET /api/contacts/src` - Downloads the original `contacts.csv` file +- `GET /api/users` - Returns parsed data from `source/users.json` +- `GET /api/users/src` - Downloads the original `users.json` file ## Sample Responses @@ -126,13 +133,26 @@ contacts_data = response.json() contacts_df = pd.DataFrame(contacts_data) print(contacts_df) -# Example 3: Extract specific information +# Example 3: Download original source files +# Download the original CSV file +csv_response = requests.get(f"{API_BASE_URL}/api/contacts/src") +with open('downloaded_contacts.csv', 'wb') as f: + f.write(csv_response.content) +print("Downloaded contacts.csv") + +# Download the original JSON file +json_response = requests.get(f"{API_BASE_URL}/api/users/src") +with open('downloaded_users.json', 'wb') as f: + f.write(json_response.content) +print("Downloaded users.json") + +# Example 4: Extract specific information contacts_response = requests.get(f"{API_BASE_URL}/api/contacts") contacts = contacts_response.json() locations = [contact['location'] for contact in contacts] print(f"Available locations: {locations}") -# Example 4: Filtering data +# Example 5: Filtering data users_response = requests.get(f"{API_BASE_URL}/api/users") users_data = users_response.json() filtered_users = [user for user in users_data.get('users', []) @@ -149,6 +169,9 @@ Output: 0 dortmund achim 1 madrid santos +Downloaded contacts.csv +Downloaded users.json + Available locations: ['dortmund', 'madrid'] Filtered users: [{'name': 'John', 'email': 'john@example.com'}] @@ -212,4 +235,4 @@ podman stop static2api docker rm static2api # or podman rm static2api -``` \ No newline at end of file +``` diff --git a/main.py b/main.py index b427f44..4d94753 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,5 @@ from fastapi import FastAPI, Request -from fastapi.responses import JSONResponse +from fastapi.responses import JSONResponse, FileResponse from fastapi.middleware.cors import CORSMiddleware import os import csv @@ -47,6 +47,7 @@ def register_api_endpoints(): if file_path.is_file(): endpoint_name = file_path.stem route = f"/api/{endpoint_name}" + src_route = f"/api/{endpoint_name}/src" # Skip if route already exists if any(route == route_info.path for route_info in app.routes): @@ -64,8 +65,13 @@ def register_api_endpoints(): content={"error": f"Failed to load CSV: {str(e)}"} ) - # Add the route + # Create a closure for serving the original file + async def get_csv_src(request: Request, file_path=file_path): + return FileResponse(file_path, media_type='text/csv', filename=file_path.name) + + # Add the routes app.add_api_route(route, get_csv_data, methods=["GET"]) + app.add_api_route(src_route, get_csv_src, methods=["GET"]) elif file_path.suffix.lower() == '.json': # Create a closure to capture the current file_path @@ -79,8 +85,13 @@ def register_api_endpoints(): content={"error": f"Failed to load JSON: {str(e)}"} ) - # Add the route + # Create a closure for serving the original file + async def get_json_src(request: Request, file_path=file_path): + return FileResponse(file_path, media_type='application/json', filename=file_path.name) + + # Add the routes app.add_api_route(route, get_json_data, methods=["GET"]) + app.add_api_route(src_route, get_json_src, methods=["GET"]) @app.middleware("http") async def check_for_new_files(request: Request, call_next):