--- name: add-api-endpoint description: > Guide for adding a new API endpoint to the codeflash-internal system. Use when adding a new endpoint, creating a route, or implementing a new API. Covers both aiservice (Django-Ninja) and cf-api (Express) endpoints including schemas, routers, authentication, URL registration, and tests. --- # Add API Endpoint Use this workflow when adding a new endpoint to either the aiservice backend or the cf-api middleware. Follow the section that matches your target service. ## Part A: AIService Endpoint (Django-Ninja) ### Step 1: Define Schemas Create request and response schemas. 1. Create or update schemas in the appropriate module (e.g., `core/shared/` for shared, `core/languages/python/` for Python-specific) 2. Use `ninja.Schema` for all request/response types: ```python from ninja import Schema class MyRequestSchema(Schema): source_code: str trace_id: str language: str = "python" class MyResponseSchema(Schema): results: list[str] class MyErrorResponseSchema(Schema): message: str ``` 3. Follow existing patterns in `core/shared/optimizer_models.py` **Checkpoint**: Schemas should use Pydantic validation. Test with `MyRequestSchema.model_validate(data)`. ### Step 2: Create the Router Create a NinjaAPI router for the endpoint. 1. Create a new module (e.g., `core/shared/my_feature.py` or `core/languages/python/my_feature/my_feature.py`) 2. Define the router and endpoint: ```python from ninja import NinjaAPI from authapp.auth import AuthenticatedRequest my_feature_api = NinjaAPI(urls_namespace="my_feature") @my_feature_api.post( "/", response={200: MyResponseSchema, 400: MyErrorResponseSchema, 500: MyErrorResponseSchema} ) async def my_endpoint( request: AuthenticatedRequest, data: MyRequestSchema ) -> tuple[int, MyResponseSchema | MyErrorResponseSchema]: # Implementation here return 200, MyResponseSchema(results=[]) ``` 3. All endpoints must be `async def` 4. Use `AuthenticatedRequest` for authenticated endpoints 5. For multi-language endpoints, add dispatch by `data.language` with lazy imports **Checkpoint**: The endpoint should handle success and error cases with proper status codes. ### Step 3: Register in urls.py Add the endpoint to `aiservice/urls.py`. 1. Import the API object: ```python from core.shared.my_feature import my_feature_api ``` 2. Add to `urlpatterns`: ```python path("ai/my-feature", my_feature_api.urls), ``` 3. Follow the naming convention: `ai/` **Checkpoint**: The endpoint should be accessible at `/ai/my-feature/`. ### Step 4: Add Tests Write tests for the endpoint. 1. Create test file in `tests/` matching the source structure 2. Test the handler function directly (not via HTTP): ```python @pytest.mark.asyncio async def test_my_endpoint(): # Mock request and data result = await my_endpoint(mock_request, mock_data) assert result[0] == 200 ``` 3. Run: `uv run pytest tests/path/test_file.py -v` **Checkpoint**: Tests pass. Run `uv run prek run --all-files`. ## Part B: CF-API Endpoint (Express) ### Step 1: Create Endpoint Handler Create the endpoint handler in `js/cf-api/endpoints/`. 1. Create `js/cf-api/endpoints/my-feature.ts`: ```typescript import { Request, Response } from "express" export async function myFeature(req: Request, res: Response) { // Implementation res.status(200).json({ results: [] }) } ``` 2. Follow existing patterns in `endpoints/` **Checkpoint**: Handler should return appropriate status codes and JSON responses. ### Step 2: Create Route File or Add to Existing Add the route to the appropriate route file. 1. If it's a new domain, create `js/cf-api/routes/my-feature.routes.ts`: ```typescript import { Router } from "express" import { addAsync } from "@awaitjs/express" import { myFeature } from "../endpoints/my-feature.js" import { ROUTES } from "../constants/index.js" const router = addAsync(Router()) as any router.postAsync(ROUTES.MY_FEATURE, myFeature) export default router ``` 2. If it belongs to an existing domain, add to the corresponding route file 3. Add the route constant to `constants/index.ts` **Checkpoint**: Route file exports a router with the endpoint registered. ### Step 3: Register in Route Index Register the route in `js/cf-api/routes/index.ts`. 1. Import the route module 2. Register in the correct section: - Before body parser: webhook routes only - Public routes: no auth required - Protected routes: after `checkForValidAPIKey` middleware 3. Apply middleware as needed (`trackUsage`, `idLimiter`, etc.) **Checkpoint**: The endpoint should be accessible with proper authentication. ### Step 4: Add Tests Write tests using the dependency injection pattern. 1. Create test file in `js/cf-api/__tests__/` 2. Use `setXxxDependencies()` / `resetXxxDependencies()` for mocking 3. Follow existing test patterns **Checkpoint**: Tests pass with `npm test`. ## Key Files Reference | File | What to modify | |------|---------------| | `core/shared/optimizer_models.py` | Schema patterns | | `aiservice/urls.py` | AIService endpoint registration | | `js/cf-api/routes/index.ts` | CF-API route registration | | `js/cf-api/constants/index.ts` | Route constants | | `authapp/auth.py` | Authentication patterns |