Skip to content

Commit 2c9d256

Browse files
committed
feat(api): Implement datasource and LLM management endpoints
- Added new endpoints for managing datasources including adding, listing, retrieving, and removing datasources. - Introduced LLM management endpoints for configuring, listing, and retrieving LLM details. - Enhanced health and readiness checks with service integration. - Refactored query execution to utilize the new service architecture. - Updated API documentation to reflect the new two-tier architecture and added endpoint descriptions. - Introduced new service classes for datasource, LLM, health, and indexing management. - Removed deprecated schema endpoints and integrated schema retrieval into the new structure.
1 parent 39e9f56 commit 2c9d256

File tree

28 files changed

+977
-204
lines changed

28 files changed

+977
-204
lines changed

docs/api/index.md

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
# API Overview
22

3-
The primary Python API surface for running NL2SQL is small and centered on:
3+
NL2SQL provides a two-tier API architecture for flexible integration:
4+
5+
## Two-Tier API Architecture
6+
7+
### 1. Core API (Python)
8+
- **Location**: Core package (`nl2sql-core`)
9+
- **Interface**: Direct Python class interface (`NL2SQL` class and low-level functions)
10+
- **Use Case**: Direct Python integration, embedded applications
11+
- **Access**: Import and use directly in Python code
12+
13+
### 2. REST API (HTTP)
14+
- **Location**: API package (`nl2sql-api`)
15+
- **Interface**: HTTP REST endpoints
16+
- **Use Case**: Remote clients, web applications, TypeScript CLI
17+
- **Access**: HTTP requests to API endpoints
18+
19+
Both APIs provide access to the same underlying NL2SQL engine functionality, allowing flexible integration options.
20+
21+
## Core API (Low-Level)
22+
23+
The low-level Python API surface is centered on:
424

525
- `NL2SQLContext` (initialization)
626
- `run_with_graph()` (pipeline execution)
727

8-
## Core API
9-
1028
```python
1129
from nl2sql.context import NL2SQLContext
1230
from nl2sql.pipeline.runtime import run_with_graph
@@ -15,6 +33,27 @@ ctx = NL2SQLContext()
1533
result = run_with_graph(ctx, "Example query")
1634
```
1735

36+
## High-Level Core API
37+
38+
The high-level Python API provides a cleaner interface through the `NL2SQL` class:
39+
40+
```python
41+
from nl2sql import NL2SQL
42+
43+
engine = NL2SQL()
44+
result = engine.run_query("Example query")
45+
```
46+
47+
## REST API
48+
49+
The REST API provides HTTP endpoints for remote access:
50+
51+
- `POST /api/v1/query` - Execute natural language queries
52+
- `GET /api/v1/schema/{datasource_id}` - Get schema information
53+
- `GET /api/v1/schema` - List available datasources
54+
- `GET /api/v1/health` - Health check
55+
- `GET /api/v1/ready` - Readiness check
56+
1857
## Supporting contracts
1958

2059
- `GraphState` (`nl2sql.pipeline.state.GraphState`)
@@ -25,3 +64,5 @@ result = run_with_graph(ctx, "Example query")
2564

2665
- Context: `packages/core/src/nl2sql/context.py`
2766
- Runtime: `packages/core/src/nl2sql/pipeline/runtime.py`
67+
- Public API: `packages/core/src/nl2sql/public_api.py`
68+
- API Package: `packages/api/src/nl2sql_api/`

docs/getting-started.md

Lines changed: 224 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
# Getting Started
22

3-
This guide walks through the minimal steps to run the NL2SQL pipeline from Python code. The runtime is configured via environment variables and the YAML/JSON files under `configs/`.
3+
This guide walks through the minimal steps to run the NL2SQL pipeline. NL2SQL provides a **two-tier API architecture** for flexible integration:
4+
5+
1. **Core API (Python)**: Direct Python integration using the `NL2SQL` class
6+
2. **REST API (HTTP)**: HTTP endpoints for remote access and web applications
7+
8+
Choose the option that best fits your use case.
49

510
## Prerequisites
611

7-
- Python 3.10+
12+
- Python 3.10+ (for Python integration)
13+
- Docker (for API container deployment, optional)
814
- A configured datasource in `configs/datasources.yaml`
915
- An LLM configuration in `configs/llm.yaml`
1016

11-
## Install the core package
17+
## Installation Options
18+
19+
### Option 1: Install Core Package from PyPI
20+
21+
```bash
22+
pip install nl2sql-core
23+
```
24+
25+
### Option 2: Install from Local Source (Development)
1226

1327
```bash
1428
pip install -e packages/core
@@ -21,7 +35,13 @@ If you are using the SQLAlchemy adapter, install it as well:
2135
pip install -e packages/adapter-sqlalchemy
2236
```
2337

24-
## Configure the system
38+
### Option 3: Install API Package
39+
40+
```bash
41+
pip install -e packages/api
42+
```
43+
44+
## Configuration
2545

2646
`NL2SQLContext` reads its configuration from these settings (see `nl2sql.common.settings.Settings`):
2747

@@ -32,11 +52,41 @@ pip install -e packages/adapter-sqlalchemy
3252

3353
Template examples exist in `configs/*.example.yaml` and `configs/*.example.json`.
3454

35-
## Index schema (required for retrieval)
55+
## Two Integration Approaches
56+
57+
### Approach 1: Core API (Python) - Direct Integration
58+
59+
Use the Core API for direct Python integration in your applications.
60+
61+
#### Initialize the Engine
62+
63+
```python
64+
from nl2sql import NL2SQL
65+
66+
# Initialize with configuration files
67+
engine = NL2SQL(
68+
ds_config_path="configs/datasources.yaml",
69+
llm_config_path="configs/llm.yaml",
70+
secrets_config_path="configs/secrets.yaml",
71+
policies_config_path="configs/policies.json"
72+
)
73+
74+
# Or initialize with default settings
75+
engine = NL2SQL()
76+
```
77+
78+
#### Index Schema (Required for Retrieval)
3679

3780
Before running queries, index your datasource schema:
3881

3982
```python
83+
# Index a specific datasource
84+
engine.index_datasource("your_datasource_id")
85+
86+
# Index all registered datasources
87+
engine.index_all_datasources()
88+
89+
# Or use the lower-level approach
4090
from nl2sql.context import NL2SQLContext
4191
from nl2sql.indexing.orchestrator import IndexingOrchestrator
4292

@@ -47,24 +97,184 @@ for adapter in ctx.ds_registry.list_adapters():
4797
orchestrator.index_datasource(adapter)
4898
```
4999

50-
## Run a query
100+
#### Run Queries
51101

52102
```python
53-
from nl2sql.context import NL2SQLContext
54-
from nl2sql.pipeline.runtime import run_with_graph
103+
from nl2sql.auth.models import UserContext
55104

56-
ctx = NL2SQLContext()
57-
result = run_with_graph(ctx, "Top 5 customers by revenue last quarter?")
105+
# Create a user context (optional)
106+
user_ctx = UserContext(
107+
user_id="user123",
108+
roles=["admin"]
109+
)
110+
111+
# Run a natural language query
112+
result = engine.run_query(
113+
"Top 5 customers by revenue last quarter?",
114+
user_context=user_ctx
115+
)
116+
117+
print(result.final_answer)
118+
print(result.sql)
119+
print(result.errors)
120+
```
121+
122+
#### Manage Datasources Programmatically
123+
124+
```python
125+
# Add a datasource programmatically
126+
engine.add_datasource({
127+
"id": "my_postgres_db",
128+
"description": "My PostgreSQL database",
129+
"connection": {
130+
"type": "postgres",
131+
"host": "localhost",
132+
"port": 5432,
133+
"database": "mydb",
134+
"user": "${SECRET_POSTGRES_USER}",
135+
"password": "${SECRET_POSTGRES_PASSWORD}"
136+
}
137+
})
138+
139+
# List all datasources
140+
datasources = engine.list_datasources()
141+
print(datasources)
142+
```
143+
144+
#### Configure LLMs Programmatically
58145

146+
```python
147+
# Configure an LLM programmatically
148+
engine.configure_llm({
149+
"name": "my_openai_model",
150+
"provider": "openai",
151+
"model": "gpt-4o",
152+
"api_key": "${SECRET_OPENAI_API_KEY}",
153+
"temperature": 0.0
154+
})
155+
```
156+
157+
### Approach 2: REST API (HTTP) - Remote Access
158+
159+
Use the REST API for remote access, web applications, or when you need HTTP-based integration.
160+
161+
#### Start the API Server
162+
163+
```bash
164+
# Using the CLI command
165+
nl2sql-api --host 0.0.0.0 --port 8000 --reload
166+
167+
# Or using uvicorn directly
168+
uvicorn nl2sql_api.main:app --host 0.0.0.0 --port 8000 --reload
169+
```
170+
171+
#### Use the REST API
172+
173+
Once the server is running, you can make HTTP requests:
174+
175+
```bash
176+
# Execute a query
177+
curl -X POST http://localhost:8000/api/v1/query \
178+
-H "Content-Type: application/json" \
179+
-d '{
180+
"natural_language": "Top 5 customers by revenue last quarter?",
181+
"datasource_id": "your_datasource_id",
182+
"execute": true
183+
}'
184+
185+
# Get schema for a specific datasource
186+
curl http://localhost:8000/api/v1/schema/your_datasource_id
187+
188+
# List all datasources
189+
curl http://localhost:8000/api/v1/schema
190+
191+
# Add a new datasource
192+
curl -X POST http://localhost:8000/api/v1/datasource \
193+
-H "Content-Type: application/json" \
194+
-d '{
195+
"config": {
196+
"id": "my_postgres_db",
197+
"description": "My PostgreSQL database",
198+
"connection": {
199+
"type": "postgres",
200+
"host": "localhost",
201+
"port": 5432,
202+
"database": "mydb",
203+
"user": "${SECRET_POSTGRES_USER}",
204+
"password": "${SECRET_POSTGRES_PASSWORD}"
205+
}
206+
}
207+
}'
208+
209+
# List all registered datasources
210+
curl http://localhost:8000/api/v1/datasource
211+
212+
# Configure an LLM
213+
curl -X POST http://localhost:8000/api/v1/llm \
214+
-H "Content-Type: application/json" \
215+
-d '{
216+
"config": {
217+
"name": "my_openai_model",
218+
"provider": "openai",
219+
"model": "gpt-4o",
220+
"api_key": "${SECRET_OPENAI_API_KEY}",
221+
"temperature": 0.0
222+
}
223+
}'
224+
225+
# Index a specific datasource
226+
curl -X POST http://localhost:8000/api/v1/index/my_postgres_db
227+
228+
# Index all datasources
229+
curl -X POST http://localhost:8000/api/v1/index-all
230+
231+
# Get index status
232+
curl http://localhost:8000/api/v1/index/status
233+
234+
# Health check
235+
curl http://localhost:8000/api/v1/health
236+
```
237+
238+
#### Python Client for REST API
239+
240+
You can also use Python to interact with the REST API:
241+
242+
```python
243+
import requests
244+
245+
# Execute a query via REST API
246+
response = requests.post("http://localhost:8000/api/v1/query", json={
247+
"natural_language": "Top 5 customers by revenue last quarter?",
248+
"datasource_id": "your_datasource_id",
249+
"execute": True
250+
})
251+
252+
result = response.json()
59253
print(result.get("final_answer"))
60-
print(result.get("errors"))
61254
```
62255

63-
## Execution flag
256+
## API Comparison
257+
258+
| Feature | Core API (Python) | REST API (HTTP) |
259+
|---------|------------------|-----------------|
260+
| **Latency** | Lower (direct call) | Higher (network round-trip) |
261+
| **Deployment** | Embedded in your app | Separate service |
262+
| **Scaling** | Scale with your app | Independent scaling |
263+
| **Security** | App-level security | Network-level security |
264+
| **Use Cases** | Embedded, internal tools | Web apps, remote clients |
265+
| **Configuration** | Python code | HTTP requests |
266+
267+
## Execution Flag
268+
269+
Both APIs accept an `execute` flag that determines whether to execute the generated SQL against the database:
64270

65-
`run_with_graph()` accepts an `execute` flag and passes it to `build_graph()`. The current graph builder does not branch on this flag, so any execution gating must be implemented inside nodes or executors.
271+
- `execute=True` (default): Execute the SQL and return results
272+
- `execute=False`: Return the generated SQL without execution
66273

67-
## Next steps
274+
## Next Steps
68275

69276
- See `configuration/system.md` for configuration details and environment variable mapping.
70277
- See `deployment/architecture.md` for production deployment guidance.
278+
- See `api/index.md` for detailed API documentation.
279+
- See `packages/core/PUBLIC_API_DOCS.md` for Core API reference.
280+
- See `packages/api/API_DOCS.md` for REST API reference.

packages/adapter-sdk/src/nl2sql_adapter_sdk/protocols.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@ def get_dialect(self) -> str:
3939
def test_connection(self) -> bool:
4040
"""Test if the connection to the datasource can be established."""
4141
...
42+
43+
def get_details(self) -> Dict[str, Any]:
44+
"""Return detailed information about the datasource."""
45+
...

packages/adapter-sqlalchemy/src/nl2sql_sqlalchemy_adapter/adapter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,3 +473,4 @@ def test_connection(self) -> bool:
473473
except Exception as e:
474474
logger.error(f"Connection test failed for {self}: {e}")
475475
return False
476+

0 commit comments

Comments
 (0)