Prompt file imported from m-rishabh-007/AI_ASSURANCE_PLATFORM (
.github/prompts/create_fastapi_module.prompt.md). Fill in{{MODULE_NAME}},{{router_file_name}},{{module_name}},{{service_module_name}},{{route_prefix}},{{tag_name}}before use. Copyright stays with the author.
Create a FastAPI Module Endpoint
Use this prompt when adding a new module route or extending an existing one.
What to generate
Generate a complete FastAPI router for the implementation module named {{MODULE_NAME}}.
The router must follow the thin-handler pattern described in backend.instructions.md.
It must not contain business logic.
The router file lives at:
backend/routers/{{router_file_name}}.py
Read first before generating
Before generating code, read:
backend.instructions.mdapi_contract.mdinput_templates.mdmodule_specs.md
Do not invent routes, field names, module names, or result shapes that conflict with those files.
Core router rules
The router must:
- be thin
- delegate all business logic to the service layer
- validate only at the boundary level when appropriate
- return typed response models
- raise
HTTPExceptionwith appropriate status codes - never perform heavy computation directly
- never duplicate Celery task logic
- never directly parse uploaded files beyond what is needed to pass them to the service layer
Required endpoints for every module router
Every implementation module router must expose these three endpoints as a minimum:
-
POST <module run path>- accepts the module run request
- creates a RunFlow
- registers uploaded files
- validates input schema through service logic
- enqueues the Celery task
- returns immediately with
run_idandstatus: NOT_STARTED
-
GET <module run details path>- fetches the RunFlow record
- returns the current run state and summary/artifact references
-
GET <module results path>- returns the detailed structured results for a completed run
- the response shape must align with
docs/module_specs.mdanddocs/api_contract.md
Canonical module names
Use these canonical module identifiers only:
adversarialgenai_evaltraditional_ai_data_qualitytraditional_ai_model_evaldefectssynthetic_datacibt
Do not invent short aliases like:
data_qualitymodel_evaldefectgenai
unless the repository explicitly defines them elsewhere.
Route mapping rules
Do not assume every module uses the route pattern:
/{{module_name}}/run
The actual route prefix depends on the module.
Use this exact mapping:
| Canonical module name | Router file | Route prefix |
|---|---|---|
adversarial |
adversarial.py |
/adversarial |
genai_eval |
genai_eval.py |
/genai-eval |
traditional_ai_data_quality |
traditional_ai.py or dedicated router if later split |
/traditional-ai/data-quality |
traditional_ai_model_eval |
traditional_ai.py or dedicated router if later split |
/traditional-ai/model-eval |
defects |
defects.py |
/defects |
synthetic_data |
synthetic_data.py |
/synthetic-data |
cibt |
cibt.py |
/cibt |
Required endpoint mapping per module
For adversarial:
POST /adversarial/runGET /adversarial/runs/{run_id}GET /adversarial/runs/{run_id}/results
For genai_eval:
POST /genai-eval/runGET /genai-eval/runs/{run_id}GET /genai-eval/runs/{run_id}/results
For traditional_ai_data_quality:
POST /traditional-ai/data-quality/runGET /traditional-ai/data-quality/runs/{run_id}GET /traditional-ai/data-quality/runs/{run_id}/results
For traditional_ai_model_eval:
POST /traditional-ai/model-eval/runGET /traditional-ai/model-eval/runs/{run_id}GET /traditional-ai/model-eval/runs/{run_id}/results
For defects:
POST /defects/runGET /defects/runs/{run_id}GET /defects/runs/{run_id}/results
For synthetic_data:
POST /synthetic-data/runGET /synthetic-data/runs/{run_id}GET /synthetic-data/runs/{run_id}/results
For cibt:
POST /cibt/runGET /cibt/runs/{run_id}GET /cibt/runs/{run_id}/results
Request style rules
JSON-only endpoints
Use JSON request models for endpoints that do not upload files.
File-upload endpoints
If the module accepts files plus other fields, the endpoint must be compatible with multipart/form-data.
Use FastAPI request handling patterns that support:
UploadFileFile(...)Form(...)
Prefer Annotated[...] style where appropriate.
Do not incorrectly force file-upload endpoints into pure JSON request-body models.
Service delegation rules
The router must delegate to the service layer for:
- RunFlow creation
- file registration
- schema validation
- task enqueueing
- run lookup
- result retrieval
The router must not:
- compute metrics
- open large files and process them directly
- implement report generation logic
- implement logging logic
- manually update multiple DB tables inline unless the service API explicitly requires it
Response model rules
Use typed response models from schemas/.
At minimum:
- run creation and run detail endpoints should return
RunFlowResponse - result endpoints should return module-specific result schemas when those exist
- if module-specific result schemas are not yet implemented, return a clearly typed structured response model instead of untyped
dictwhere practical
Do not return raw ORM objects.
Error handling rules
Map errors consistently:
400for malformed form/file requests or results requested before completion401for unauthenticated access404for missing run IDs422for typed validation failures500for unexpected internal failures
Use clear HTTPException messages.
Code template pattern
Use this structure as the baseline and adapt the route prefix to the correct module mapping above:
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form
from sqlalchemy.orm import Session
from database import get_db
from schemas.run_flow import RunFlowResponse
from services import {{service_module_name}}
router = APIRouter(prefix="{{route_prefix}}", tags=["{{tag_name}}"])
@router.post("/run", response_model=RunFlowResponse, status_code=201)
async def create_run(
db: Session = Depends(get_db),
# add Form(...) and File(...) params as required by the module contract
):
try:
return await {{service_module_name}}.create_run(...)
except ValueError as e:
raise HTTPException(status_code=422, detail=str(e))
except FileNotFoundError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception:
raise HTTPException(status_code=500, detail="Failed to create run")
@router.get("/runs/{run_id}", response_model=RunFlowResponse)
async def get_run(run_id: str, db: Session = Depends(get_db)) -> RunFlowResponse:
run = await {{service_module_name}}.get_run(db, run_id)
if not run:
raise HTTPException(status_code=404, detail="Run not found")
return run
@router.get("/runs/{run_id}/results")
async def get_results(run_id: str, db: Session = Depends(get_db)):
try:
return await {{service_module_name}}.get_results(db, run_id)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except LookupError:
raise HTTPException(status_code=404, detail="Run not found")
except Exception:
raise HTTPException(status_code=500, detail="Failed to fetch results")
Module-specific endpoint notes
Adversarial
Must support:
file upload for attack_file
optional safety_policy_file
form fields like flow_name, project_id, model_endpoint_url, grader_model_name, system_prompt
GenAI Eval
Must support:
file upload for evaluation_file
form fields like flow_name, project_id, model_endpoint_url, granularity, baseline_run_id
Traditional AI Data Quality
Must support:
current_file
optional reference_file
optional target_column
optional thresholds_json
Traditional AI Model Eval
Must support:
dataset_file
model_type
target_column
model_endpoint_url
Defects
Must support:
defect_file
optional source_metadata
Synthetic Data
Must support:
sample_file
row_count
optional generation_instruction
CIBT
Must support:
change_artifact_file
traceability_matrix_file
optional requirements_mapping_file
optional source_metadata
If using a shared router file
If both Traditional AI modules live in one shared router file such as:
backend/routers/traditional_ai.py
that is allowed.
In that case:
keep two clearly separated route groups
keep service calls explicit per module
do not blur data quality and model evaluation logic together
Final generation rules
When generating a router:
use the real route prefix from the mapping table
use canonical module names
respect file-vs-form-vs-JSON request style
keep handlers thin
keep result endpoints aligned with api_contract.md
do not generate generic paths that contradict the final contract