Skip to content

Commit 1308c11

Browse files
CopilotMte90
andcommitted
Add comprehensive OpenAPI documentation for all API endpoints
Co-authored-by: Mte90 <403283+Mte90@users.noreply.github.com>
1 parent 7d8df89 commit 1308c11

File tree

1 file changed

+106
-16
lines changed

1 file changed

+106
-16
lines changed

main.py

Lines changed: 106 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,40 @@ async def lifespan(app: FastAPI):
5252

5353
yield
5454

55-
app = FastAPI(lifespan=lifespan)
55+
app = FastAPI(
56+
lifespan=lifespan,
57+
title="PicoCode API",
58+
description="Local Codebase Assistant with RAG (Retrieval-Augmented Generation). "
59+
"Index codebases, perform semantic search, and query with AI assistance.",
60+
version="0.2.0",
61+
docs_url="/docs",
62+
redoc_url="/redoc",
63+
openapi_tags=[
64+
{"name": "projects", "description": "Project management operations"},
65+
{"name": "indexing", "description": "Code indexing operations"},
66+
{"name": "query", "description": "Semantic search and code queries"},
67+
{"name": "health", "description": "Health and status checks"},
68+
]
69+
)
5670
templates = Jinja2Templates(directory="templates")
5771
if os.path.isdir("static"):
5872
app.mount("/static", StaticFiles(directory="static"), name="static")
5973

6074

6175
# Project Management API (PyCharm-compatible)
62-
@app.post("/api/projects")
76+
@app.post("/api/projects", tags=["projects"], summary="Create or get a project")
6377
def api_create_project(request: CreateProjectRequest):
64-
"""Create or get a project with per-project database."""
78+
"""
79+
Create or get a project with per-project database.
80+
81+
- **path**: Absolute path to project directory (required)
82+
- **name**: Optional project name (defaults to directory name)
83+
84+
Returns project metadata including:
85+
- **id**: Unique project identifier
86+
- **database_path**: Path to project's SQLite database
87+
- **status**: Current project status
88+
"""
6589

6690
try:
6791
# Validate input
@@ -83,9 +107,18 @@ def api_create_project(request: CreateProjectRequest):
83107
return JSONResponse({"error": "Internal server error"}, status_code=500)
84108

85109

86-
@app.get("/api/projects")
110+
@app.get("/api/projects", tags=["projects"], summary="List all projects")
87111
def api_list_projects():
88-
"""List all projects."""
112+
"""
113+
List all registered projects.
114+
115+
Returns array of project objects with metadata:
116+
- **id**: Unique project identifier
117+
- **name**: Project name
118+
- **path**: Project directory path
119+
- **status**: Current status (created, indexing, ready, error)
120+
- **last_indexed_at**: Last indexing timestamp
121+
"""
89122
try:
90123
projects = list_projects()
91124
return JSONResponse(projects)
@@ -94,9 +127,15 @@ def api_list_projects():
94127
return JSONResponse({"error": "Failed to list projects"}, status_code=500)
95128

96129

97-
@app.get("/api/projects/{project_id}")
130+
@app.get("/api/projects/{project_id}", tags=["projects"], summary="Get project by ID")
98131
def api_get_project(project_id: str):
99-
"""Get project details by ID."""
132+
"""
133+
Get project details by ID.
134+
135+
- **project_id**: Unique project identifier
136+
137+
Returns project metadata or 404 if not found.
138+
"""
100139
try:
101140
project = get_project_by_id(project_id)
102141
if not project:
@@ -107,9 +146,16 @@ def api_get_project(project_id: str):
107146
return JSONResponse({"error": "Failed to retrieve project"}, status_code=500)
108147

109148

110-
@app.delete("/api/projects/{project_id}")
149+
@app.delete("/api/projects/{project_id}", tags=["projects"], summary="Delete a project")
111150
def api_delete_project(project_id: str):
112-
"""Delete a project and its database."""
151+
"""
152+
Delete a project and its database.
153+
154+
- **project_id**: Unique project identifier
155+
156+
Permanently removes the project and all indexed data.
157+
Returns 404 if project not found.
158+
"""
113159
try:
114160
delete_project(project_id)
115161
return JSONResponse({"success": True})
@@ -121,9 +167,23 @@ def api_delete_project(project_id: str):
121167
return JSONResponse({"error": "Failed to delete project"}, status_code=500)
122168

123169

124-
@app.post("/api/projects/index")
170+
@app.post("/api/projects/index", tags=["indexing"], summary="Index a project")
125171
def api_index_project(http_request: Request, request: IndexProjectRequest, background_tasks: BackgroundTasks):
126-
"""Index/re-index a project in the background."""
172+
"""
173+
Index or re-index a project in the background.
174+
175+
- **project_id**: Unique project identifier
176+
177+
Starts background indexing process:
178+
- Scans project directory for code files
179+
- Generates embeddings for semantic search
180+
- Uses incremental indexing (skips unchanged files)
181+
182+
Rate limit: 10 requests per minute per IP.
183+
184+
Returns immediately with status "indexing".
185+
Poll project status to check completion.
186+
"""
127187
# Rate limiting for indexing operations (more strict)
128188
client_ip = _get_client_ip(http_request)
129189
allowed, retry_after = indexing_limiter.is_allowed(client_ip)
@@ -167,9 +227,27 @@ def index_callback():
167227
return JSONResponse({"error": "Failed to start indexing"}, status_code=500)
168228

169229

170-
@app.post("/api/query")
230+
@app.post("/api/query", tags=["query"], summary="Semantic search query")
171231
def api_query(http_request: Request, request: QueryRequest):
172-
"""Query a project using semantic search (PyCharm-compatible)."""
232+
"""
233+
Query a project using semantic search.
234+
235+
- **project_id**: Unique project identifier
236+
- **query**: Search query text
237+
- **top_k**: Number of results to return (default: 5, max: 20)
238+
239+
Performs semantic search using vector embeddings:
240+
- Generates embedding for query
241+
- Finds most similar code chunks
242+
- Returns ranked results with scores
243+
244+
Rate limit: 100 requests per minute per IP.
245+
246+
Returns:
247+
- **results**: Array of matching code chunks
248+
- **project_id**: Project identifier
249+
- **query**: Original query text
250+
"""
173251
# Rate limiting
174252
client_ip = _get_client_ip(http_request)
175253
allowed, retry_after = query_limiter.is_allowed(client_ip)
@@ -206,13 +284,25 @@ def api_query(http_request: Request, request: QueryRequest):
206284

207285

208286

209-
@app.get("/api/health")
287+
@app.get("/api/health", tags=["health"], summary="Health check")
210288
def api_health():
211-
"""Health check endpoint."""
289+
"""
290+
Health check endpoint for monitoring and status verification.
291+
292+
Returns:
293+
- **status**: "ok" if service is running
294+
- **version**: API version
295+
- **features**: List of enabled features
296+
297+
Use this endpoint for:
298+
- Load balancer health checks
299+
- Monitoring systems
300+
- Service availability verification
301+
"""
212302
return JSONResponse({
213303
"status": "ok",
214304
"version": "0.2.0",
215-
"features": ["rag", "per-project-db", "pycharm-api"]
305+
"features": ["rag", "per-project-db", "pycharm-api", "incremental-indexing", "rate-limiting", "caching"]
216306
})
217307

218308

0 commit comments

Comments
 (0)