Skip to main content سوق المهارات اكتشف واستكشف مهارات الذكاء الاصطناعي التي بناها المجتمع.
المهن ذات الصلة SOC
استنادا إلى تصنيف SOC المهني
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
نسخ Promptعرض تفاصيل Prompt يتجاوز الأمر المباشر Prompt المخصّص للمراجعة. افحص المصدر قبل تشغيله.
npx skills add https://github.com/CleanExpo/NodeJS-Starter-V1 --skill api-contractيبقى الأمر في سطر واحد. مرّر أفقيًا لمراجعته كاملًا قبل النسخ.
تفضّل نسخة محلية؟ نزّل الملفات المتاحة حاليًا لدى SkillsMP.
تحميل Zip جاري التحميل... المزيد من هذا المستودع Route complex requests to the right specialist agent or chain of agents. This skill acts as the central brain of an agent swarm — it analyses what the user needs, determines which specialist domain(s) are required, and coordinates parallel or sequential agent execution. Use this skill when a request spans multiple domains (e.g., "research competitors and create a pitch deck"), when you need to decide which specialist should handle an ambiguous request, or when a task requires a multi-step pipeline across different skills. Triggers on: multi-step requests, cross-domain tasks, "coordinate", "plan this out", "I need help with multiple things", or any complex request that touches more than one specialist area. Also triggers when the user seems unsure which tool or approach to use.
Hybrid DAG execution primitive combining deterministic and agentic nodes with hard iteration caps
">"
id api-contract name api-contract type skill version 1.0.0 created 20/03/2026 modified 20/03/2026 status active metadata {"author":"NodeJS-Starter-V1","version":"1.0.0","locale":"en-AU"} description >- context fork
API Contract - Typed Frontend/Backend Contracts
Ensures every API endpoint has a typed contract: Pydantic models on the backend, Zod response schemas on the frontend, and documented error responses. Bridges the gap between apps/backend/src/api/ and apps/web/lib/api/.
Description
Enforces type-safe API contracts across the FastAPI backend and Next.js frontend. Every endpoint must declare a Pydantic response_model, have a matching Zod schema on the frontend, and document error responses via OpenAPI. Prevents schema drift, untyped responses, and manual type definitions by mandating a single source of truth through the Contract Triangle pattern.
When to Apply
Positive Triggers
Creating or modifying API endpoints (FastAPI routes)
Adding frontend API calls (apiClient.get/post/put/patch/delete)
Reviewing type safety between backend responses and frontend consumers
Documenting API error responses
Planning API versioning or deprecation
User mentions: "API contract", "endpoint", "response type", "OpenAPI", "schema"
Negative Triggers
Validating user input forms (use data-validation instead)
Classifying error codes (use error-taxonomy instead)
Implementing retry logic or resilience (use retry-strategy when available)
Working on WebSocket or real-time protocols (separate concern)
Core Directives
The Contract Triangle
Backend (Pydantic) ←── Contract ──→ Frontend (Zod)
↓ ↓
response_model z.infer<typeof schema>
↓ ↓
OpenAPI spec Type-safe apiClient
Every endpoint must have:
Backend : Pydantic response_model on the route decorator
Frontend : Zod schema validating the response shape
Documentation : Error responses listed in responses={} dict
Field Name Convention
Use snake_case consistently across both sides:
class DocumentItem (BaseModel ):
created_at: datetime
error_code:
str
const documentItemSchema = z.object ({
created_at : z.string ().datetime (),
error_code : z.string (),
});
Do NOT convert to camelCase on the frontend. The API contract is snake_case end-to-end.
Backend Patterns (FastAPI + Pydantic)
Schema Location Convention The project already uses two patterns. Standardise to:
Schema Scope Location When to Use Route-specific Inline in route file Used by 1 endpoint only (e.g., DocumentCreateRequest) Shared across routes apps/backend/src/api/schemas/{domain}.pyUsed by 2+ endpoints or referenced by frontend Domain models apps/backend/src/models/Business logic models, not request/response shapes
Inline: apps/backend/src/api/routes/documents.py (DocumentItem, DocumentListResponse)
Shared: apps/backend/src/api/schemas/workflow_builder.py (WorkflowNodeResponse, etc.)
Domain: apps/backend/src/models/contractor.py (Contractor, Location, ErrorResponse)
Response Model on Every Route Every route MUST declare response_model:
@router.get(
"" ,
response_model=DocumentListResponse,
summary="List documents" ,
responses={
401 : {"model" : ErrorResponse, "description" : "Unauthorised" },
500 : {"model" : ErrorResponse, "description" : "Internal error" },
},
)
async def list_documents (... ) -> DocumentListResponse:
...
@router.get("/data" )
async def get_data () -> dict :
return {"stuff" : "things" }
Standard Response Wrappers Use consistent wrapper patterns for list endpoints:
from pydantic import BaseModel, Field
class PaginationInfo (BaseModel ):
"""Reusable pagination metadata."""
total: int = Field(description="Total matching items" )
limit: int = Field(description="Results per page" )
offset: int = Field(description="Current offset" )
pages: int = Field(description="Total number of pages" )
class PaginatedResponse (BaseModel ):
"""Generic paginated response base. Subclass with typed `data` field."""
pagination: PaginationInfo
Subclass for each domain:
class DocumentListResponse (BaseModel ):
data: list [DocumentItem]
pagination: PaginationInfo
Error Response Contract Every route should document error responses using the ErrorResponse model from error-taxonomy:
from src.models.contractor import ErrorResponse
@router.post(
"" ,
response_model=DocumentItem,
status_code=201 ,
responses={
401 : {"model" : ErrorResponse, "description" : "Unauthorised" },
422 : {"model" : ErrorResponse, "description" : "Validation error" },
409 : {"model" : ErrorResponse, "description" : "Duplicate resource" },
},
)
OpenAPI Metadata @router.get(
"/path" ,
response_model=ResponseType,
summary="Short description" ,
description="Detailed description" ,
tags=["Domain" ],
responses={...},
)
The FastAPI app already generates OpenAPI at /docs (Swagger) and /redoc.
Frontend Patterns (Zod + apiClient)
Response Schema Convention Create Zod schemas that mirror backend Pydantic models:
import * as z from 'zod' ;
const documentItemSchema = z.object ({
id : z.string (),
title : z.string (),
content : z.string ().nullable (),
metadata : z.record (z.unknown ()),
created_at : z.string (),
updated_at : z.string (),
});
const paginationSchema = z.object ({
total : z.number (),
limit : z.number (),
offset : z.number (),
pages : z.number (),
});
const documentListResponseSchema = z.object ({
data : z.array (documentItemSchema),
pagination : paginationSchema,
});
type DocumentItem = z.infer <typeof documentItemSchema>;
type DocumentListResponse = z.infer <typeof documentListResponseSchema>;
export {
documentItemSchema,
documentListResponseSchema,
type DocumentItem ,
type DocumentListResponse ,
};
Schema File Location apps/web/lib/api/
├── client.ts # Existing fetch wrapper
├── auth.ts # Existing auth API
└── schemas/ # NEW: Response schemas
├── common.ts # Pagination, ErrorResponse
├── documents.ts # Document schemas
├── workflows.ts # Workflow schemas
├── agents.ts # Agent/discovery schemas
└── contractors.ts # Contractor schemas
Validated API Calls Wrap apiClient calls with Zod parsing for runtime safety:
import { apiClient } from '@/lib/api/client' ;
import {
documentListResponseSchema,
type DocumentListResponse ,
} from '@/lib/api/schemas/documents' ;
export async function listDocuments (
params ?: { limit?: number ; offset?: number }
): Promise <DocumentListResponse > {
const query = new URLSearchParams ();
if (params?.limit ) query.set ('limit' , String (params.limit ));
if (params?.offset ) query.set ('offset' , String (params.offset ));
const raw = await apiClient.get (`/api/documents?${query} ` );
return documentListResponseSchema.parse (raw);
}
Error Response Schema Mirror the backend ErrorResponse on the frontend:
import * as z from 'zod' ;
const errorResponseSchema = z.object ({
detail : z.string (),
error_code : z.string ().optional (),
severity : z.enum (['fatal' , 'error' , 'warning' ]).optional (),
field : z.string ().optional (),
});
type ErrorResponse = z.infer <typeof errorResponseSchema>;
export { errorResponseSchema, type ErrorResponse };
Contract Checklist When adding or modifying an API endpoint:
Backend
Frontend
Cross-Stack
Versioning Strategy
URL-Based Versioning (When Ready) When the API needs breaking changes:
app.include_router(documents.router, prefix="/api/v1" , tags=["Documents v1" ])
app.include_router(documents_v2.router, prefix="/api/v2" , tags=["Documents v2" ])
Deprecation Headers Mark deprecated endpoints with headers:
from fastapi import Response
@router.get("/old-endpoint" , deprecated=True )
async def old_endpoint (response: Response ):
response.headers["Deprecation" ] = "true"
response.headers["Sunset" ] = "2026-06-01"
response.headers["Link" ] = '</api/v2/new-endpoint>; rel="successor-version"'
return {"data" : "still works" }
Breaking Change Rules A change is breaking if it:
Removes a field from a response
Changes a field's type
Makes an optional request field required
Changes the URL path or method
Removes an endpoint
A change is non-breaking if it:
Adds a new optional field to a response
Adds a new optional query parameter
Adds a new endpoint
Adds a new enum value
Detection Rules Grep for contract violations:
rg "def (get|post|put|patch|delete)_" apps/backend/src/api/routes/ | \
rg -v "response_model"
rg "-> dict" apps/backend/src/api/routes/
rg "apiClient\.(get|post|put|patch|delete)" apps/web/ | \
rg -v "Schema\.parse"
Anti-Patterns Pattern Problem Correct Approach Untyped API responses (-> dict) No compile-time or runtime validation, silent breakage Declare response_model on every route with a Pydantic model Frontend/backend schema drift Field mismatches cause runtime errors in production Mirror Pydantic models with Zod schemas; validate with .parse() No response envelope pattern Inconsistent list responses, missing pagination metadata Use PaginatedResponse wrapper with data and pagination fields Manual type synchronisation Types fall out of sync as endpoints evolve Infer frontend types via z.infer<typeof schema>, never define manually Missing error response documentation Consumers cannot handle failures gracefully Document all error codes in responses={} dict using ErrorResponse model
Checklist
Response Format [AGENT_ACTIVATED]: API Contract
[PHASE]: {Audit | Implementation | Review}
[STATUS]: {in_progress | complete}
{contract analysis or implementation guidance}
[NEXT_ACTION]: {what to do next}
Integration Points
Error Taxonomy Error responses use ErrorResponse from error-taxonomy. Every responses={} dict references the canonical error model.
Data Validation data-validation handles request validation (Zod for forms, Pydantic for bodies). api-contract handles response validation (Zod schemas mirroring Pydantic response models).
Request: User → Zod (form) → fetch → Pydantic (body) → Service
Response: Service → Pydantic (response_model) → JSON → Zod (parse) → Component
Council of Logic (Shannon Check)
Response schemas must be minimal — return only what the frontend needs
No duplicating the same schema across multiple files — compose from shared base schemas
Pagination wrapper is reusable, not redefined per domain
Australian Localisation (en-AU)
Date Format : ISO 8601 in API transit; DD/MM/YYYY in UI display
Currency : AUD ($) — amounts as integers (cents) in API, formatted in UI
Spelling : serialisation, authorisation, organisation, analyse, centre, colour
Timezone : AEST/AEDT — store UTC in database, convert in frontend