mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
171 lines
5.3 KiB
Markdown
171 lines
5.3 KiB
Markdown
|
|
---
|
||
|
|
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/<kebab-case-name>`
|
||
|
|
|
||
|
|
**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 |
|