Skip to main content

add-endpoint

Add a new FastAPI endpoint to APIView Copilot. Use for: add endpoint, new endpoint, new API route, add route, create endpoint, add API, new POST endpoint, new GET endpoint.

معلومات المصدر

المستودع
Azure/azure-sdk-tools
آخر نشاط في المصدر
٢٤ مارس ٢٠٢٦ في ١٥:٢٧
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١٣٤
التفرعات
٢٦٢

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
add-endpoint
description
Add a new FastAPI endpoint to APIView Copilot. Use for: add endpoint, new endpoint, new API route, add route, create endpoint, add API, new POST endpoint, new GET endpoint.
# Add a FastAPI Endpoint ## Checklist When adding a new endpoint, follow every step below. ### 1. Define Pydantic request/response models - Place models near where they're used — in `app.py` for endpoint-specific models, or in `src/_models.py` for shared/reusable models. - **All multi-word field names MUST use camelCase aliases.** Never expose snake_case in the JSON API. - Add `class Config` with `populate_by_name = True` on any model that has aliases so it can be constructed with either the Python name or the alias. - Use `Field(...)` for required fields, `Field(None, ...)` or `Field(default=..., ...)` for optional ones. - Every model must have a triple-double-quote docstring. #### Example ```python class MyFeatureRequest(BaseModel): """Request model for my feature.""" review_id: str = Field(..., alias="reviewId") language: str include_deleted: bool = Field(False, alias="includeDeleted") max_results: Optional[int] = Field(None, alias="maxResults") class Config: """Configuration for Pydantic model.""" populate_by_name = True class MyFeatureResponse(BaseModel): """Response model for my feature.""" job_id: str = Field(..., alias="jobId") result_count: int = Field(..., alias="resultCount") class Config: """Configuration for Pydantic model.""" populate_by_name = True ``` #### Rules | Rule | Correct | Wrong | |---|---|---| | JSON field casing | `"reviewId"` | `"review_id"` | | Alias declaration | `Field(..., alias="reviewId")` | bare `review_id: str` for multi-word names | | Config on aliased models | `class Config: populate_by_name = True` | missing Config | | Single-word fields | `language: str` (no alias needed) | `language: str = Field(..., alias="language")` | ### 2. Define the endpoint function - Use `@app.post(...)` or `@app.get(...)` etc. with `response_model=` pointing to the response model. - Set `status_code=` when it's not the default 200 (e.g., `202` for async jobs). - Add `Depends(require_roles(...))` for authentication. Use `AppRole.READER` / `AppRole.APP_READER` for read-only, `AppRole.WRITER` / `AppRole.APP_WRITER` for mutations. - Add a docstring describing the endpoint. - Wrap business logic in try/except and raise `HTTPException` with appropriate status codes. - For long-running work, use `asyncio.to_thread(...)` or background tasks. #### Example ```python @app.post("/my-feature", response_model=MyFeatureResponse) async def my_feature( request: MyFeatureRequest, _claims=Depends(require_roles(AppRole.READER, AppRole.APP_READER)), ): """Handle my feature requests.""" try: result = await asyncio.to_thread(do_work, review_id=request.review_id) return MyFeatureResponse(job_id=result.id, result_count=result.count) except Exception as e: logger.error("Error in /my-feature: %s", e, exc_info=True) raise HTTPException(status_code=500, detail="Internal server error") from e ``` ### 3. Serialization FastAPI automatically serializes response models **by alias** when `response_model` is set. This means: - The JSON response will use the alias names (`jobId`, `resultCount`), not the Python names. - No extra `by_alias=True` call is needed — FastAPI handles this via the `response_model`. - When constructing a response object in code, use the **Python field names**: `MyFeatureResponse(job_id=..., result_count=...)`. ### 4. Add a corresponding CLI command Every endpoint must have a CLI command in `cli.py` with a `--remote` flag. The **core logic must be shared** between remote and local paths to the maximum extent practical. #### Architecture: shared core function Extract the business logic into a standalone function (in `src/` or at module level in `cli.py`) that both the endpoint and the CLI's local path call. The CLI's `--remote` path sends an HTTP request to the endpoint instead. ``` ┌─────────────┐ │ core logic │ ← shared function in src/ │ (do_work) │ └──────┬──────┘ │ ┌────────────┴────────────┐ │ │ ┌──────┴──────┐ ┌──────┴──────┐ │ app.py │ │ cli.py │ │ endpoint │ │ (local) │ └─────────────┘ └─────────────┘ │ if --remote: HTTP POST → endpoint ``` #### CLI handler pattern ```python def my_feature(language: str, review_id: str, include_deleted: bool = False, remote: bool = False): """Describe the command.""" if remote: # Remote: HTTP call to the deployed endpoint settings = SettingsManager() base_url = settings.get("WEBAPP_ENDPOINT") payload = {"language": language, "reviewId": review_id, "includeDeleted": include_deleted} resp = requests.post( f"{base_url}/my-feature", json=payload, headers=_build_auth_header(), timeout=60 ) if resp.status_code == 200: print(json.dumps(resp.json(), indent=2)) else: print(f"Error: {resp.status_code} - {resp.text}") else: # Local: call shared core logic directly result = do_work(language=language, review_id=review_id, include_deleted=include_deleted) print(json.dumps(result, indent=2)) ``` Key rules: - The `--remote` payload must use **camelCase** keys matching the endpoint's request model aliases. - Local mode calls the **same core function** that the endpoint calls. - Use `_build_auth_header()` for remote authentication. - Use `SettingsManager().get("WEBAPP_ENDPOINT")` for the base URL. #### Register the command In `CliCommandsLoader.load_command_table`, add the command to the appropriate `CommandGroup`: ```python with CommandGroup(self, "review", "__main__#{}") as g: # ... existing commands ... g.command("my-feature", "my_feature") ``` Register any command-specific arguments in `load_arguments`: ```python with ArgumentsContext(self, "review my-feature") as ac: ac.argument("review_id", options_list=["--review-id", "-r"], help="The review ID.") ac.argument("include_deleted", action="store_true", help="Include deleted items.") ``` Notes: - `--remote` and `--language` are already registered globally — don't re-register them. - Knack maps function parameter names to CLI flags automatically (e.g., `review_id` → `--review-id`). - Use `type=resolve_language_to_canonical` for language params (already global). ### 5. Common pitfalls to avoid - **Never return raw dicts with snake_case keys** from an endpoint. Always use a typed response model. - **Never omit `alias=`** on multi-word field names. The API contract is camelCase. - **Never use `model_config = ConfigDict(alias_generator=to_camel)`** — this project uses explicit `alias=` per field, not automatic generators. - **Never forget `populate_by_name = True`** on models with aliases — without it, the model can't be constructed using Python field names. - **Never duplicate core logic** between the endpoint and the CLI local path. Extract it into a shared function in `src/`. - **Never use snake_case keys in the remote payload** — the `--remote` path must send camelCase keys matching the request model aliases. - **Never re-register `--remote` or `--language`** in command-specific `ArgumentsContext` — they are global.
عرض على GitHub