FastAPI SQL Query Engine
Project description
DBAnu - FastAPI SQL Query Engine
DBAnu is a lightweight Python library that simplifies creating FastAPI endpoints for SQL queries. It provides a clean, type-safe interface for exposing database queries as RESTful APIs with built-in support for filtering, pagination, dependency injection, and middleware.
Features
- Type-Safe Query Generation: Automatically generate FastAPI routes from SQL queries
- Flexible Filtering: Support for complex filtering with Pydantic models
- Built-in Pagination: Automatic limit/offset pagination support
- FastAPI Integration: Seamless integration with FastAPI dependencies and middleware
- Multiple Database Support: SQLite, PostgreSQL, MySQL, and custom engines
- Dependency Injection: Access FastAPI dependencies in middleware
- Middleware System: Custom middleware for logging, authentication, authorization, and more
Installation
pip install dbanu
Quick Start
Basic Usage
Create a simple FastAPI endpoint with SQLite:
from fastapi import FastAPI
from dbanu import serve_select, SQLiteQueryEngine
app = FastAPI()
# Create a SQLite query engine
query_engine = SQLiteQueryEngine()
# Register a simple endpoint
serve_select(
app=app,
query_engine=query_engine,
path="/api/books",
select_query="SELECT id, title, author FROM books LIMIT ? OFFSET ?",
select_param=lambda filters, limit, offset: [limit, offset]
)
Advanced Usage with Filtering
from pydantic import BaseModel
from fastapi import FastAPI
from dbanu import serve_select, SQLiteQueryEngine
app = FastAPI()
# Define filter model
class BookFilter(BaseModel):
author: str | None = None
min_year: int | None = None
# Define data model
class BookData(BaseModel):
id: int
title: str
author: str
year: int
# Create query engine
query_engine = SQLiteQueryEngine()
# Register endpoint with filtering
serve_select(
app=app,
query_engine=query_engine,
path="/api/books",
filter_model=BookFilter,
data_model=BookData,
select_query=(
"SELECT id, title, author, year FROM books "
"WHERE (author = ? OR ? IS NULL) "
"AND (year >= ? OR ? IS NULL) "
"LIMIT ? OFFSET ?"
),
select_param=lambda filters, limit, offset: [
filters.author, filters.author,
filters.min_year, filters.min_year,
limit, offset
],
count_query=(
"SELECT COUNT(*) FROM books "
"WHERE (author = ? OR ? IS NULL) "
"AND (year >= ? OR ? IS NULL)"
),
count_param=lambda filters: [
filters.author, filters.author,
filters.min_year, filters.min_year
]
)
Full Example with Dependencies and Middleware
import sqlite3
from typing import Any
from pydantic import BaseModel
from fastapi import FastAPI, Depends
from dbanu import serve_select, SQLiteQueryEngine
app = FastAPI()
# Custom query engine with setup
class MyQueryEngine(SQLiteQueryEngine):
def _setup_database(self, conn: sqlite3.Connection):
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
author TEXT NOT NULL,
year INTEGER NOT NULL
)
""")
books = [
(1, "The Great Gatsby", "F. Scott Fitzgerald", 1925),
(2, "To Kill a Mockingbird", "Harper Lee", 1960),
]
cursor.executemany("INSERT OR REPLACE INTO books VALUES (?, ?, ?, ?)", books)
conn.commit()
# FastAPI dependencies
async def get_current_user():
return {"user_id": 1, "username": "demo_user"}
async def rate_limit_check():
return True
# Middleware functions
def logging_middleware(filters: BaseModel, limit: int, offset: int, dependency_results: dict[str, Any], next_handler):
user_info = dependency_results.get('get_current_user', {})
username = user_info.get('username', 'anonymous')
print(f"[LOG] Request from {username}: filters={filters.model_dump()}")
result = next_handler()
print(f"[LOG] Response: {len(result.data)} items")
return result
def authorization_middleware(filters: BaseModel, limit: int, offset: int, dependency_results: dict[str, Any], next_handler):
from fastapi import HTTPException
current_user = dependency_results.get('get_current_user')
if not current_user:
raise HTTPException(status_code=401, detail="Authentication required")
if current_user.get('user_id') != 1:
raise HTTPException(status_code=403, detail="Access forbidden")
return next_handler()
# Pydantic models
class BookFilter(BaseModel):
author: str | None = None
min_year: int | None = None
class BookData(BaseModel):
id: int
title: str
author: str
year: int
# Create query engine
query_engine = MyQueryEngine()
# Register endpoint with all features
serve_select(
app=app,
query_engine=query_engine,
path="/api/v1/books",
filter_model=BookFilter,
data_model=BookData,
select_query=(
"SELECT id, title, author, year FROM books "
"WHERE (author = ? OR ? IS NULL) "
"AND (year >= ? OR ? IS NULL) "
"LIMIT ? OFFSET ?"
),
select_param=lambda filters, limit, offset: [
filters.author, filters.author,
filters.min_year, filters.min_year,
limit, offset
],
count_query=(
"SELECT COUNT(*) FROM books "
"WHERE (author = ? OR ? IS NULL) "
"AND (year >= ? OR ? IS NULL)"
),
count_param=lambda filters: [
filters.author, filters.author,
filters.min_year, filters.min_year
],
dependencies=[Depends(get_current_user), Depends(rate_limit_check)],
middlewares=[logging_middleware, authorization_middleware]
)
@app.get("/")
def read_root():
return {"message": "DBAnu Books API is running!"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Even More Complex Example
No, no such thing. If you really need something more complex, you probably need to actually code your own router.
Database Engines
SQLite
from dbanu import SQLiteQueryEngine
query_engine = SQLiteQueryEngine()
PostgreSQL
from dbanu import PostgreSQLQueryEngine
query_engine = PostgreSQLQueryEngine(
host="localhost",
port=5432,
database="mydb",
user="user",
password="password"
)
MySQL
from dbanu import MySQLQueryEngine
query_engine = MySQLQueryEngine(
host="localhost",
port=3306,
database="mydb",
user="user",
password="password"
)
API Reference
serve_select Parameters
app: FastAPI application instancequery_engine: Database query engine (SQLite, PostgreSQL, or MySQL)select_query: SQL SELECT query stringselect_param: Function to generate query parameters from filterscount_query: Optional SQL COUNT query for paginationcount_param: Function to generate COUNT query parameterspath: API endpoint path (default: "/get")filter_model: Pydantic model for filteringdata_model: Pydantic model for response datadependencies: List of FastAPI dependenciesmiddlewares: List of middleware functions
Middleware Signature
Middleware functions should have the following signature:
def middleware_name(
filters: BaseModel,
limit: int,
offset: int,
dependency_results: dict[str, Any],
next_handler: Callable
) -> Any:
# Your middleware logic
return next_handler()
Running the Example
python -m example.server
Visit http://localhost:8000/api/v1/books to test the API.
License
MIT
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 dbanu-0.0.1.tar.gz.
File metadata
- Download URL: dbanu-0.0.1.tar.gz
- Upload date:
- Size: 5.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.4 CPython/3.11.9 Linux/5.15.153.1-microsoft-standard-WSL2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f352c0475f55198a4d5186901fbc6854084e0b1b1d13d7d31f7c562491cca64f
|
|
| MD5 |
4997418a5ae8a275148fa7769ae6c45b
|
|
| BLAKE2b-256 |
393dfd7ce0872c5917c078109c860416662c4041ac90d683409d37221d7062ae
|
File details
Details for the file dbanu-0.0.1-py3-none-any.whl.
File metadata
- Download URL: dbanu-0.0.1-py3-none-any.whl
- Upload date:
- Size: 7.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.4 CPython/3.11.9 Linux/5.15.153.1-microsoft-standard-WSL2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a683129b9195f576a20ce7efc8abdc1f89f555ec092fe085d2760532f3ee8663
|
|
| MD5 |
83415f0781249007ca5e8c5f2eed375b
|
|
| BLAKE2b-256 |
895d9f8fe9bfe67f71456be8d064e48f97ba69976eec4f9ab6e9b1d51775ba0a
|