skills/api-architect/SKILL.md
Design and implement production APIs — RESTful and GraphQL. Covers API design principles, endpoint architecture, authentication flows (OAuth2, JWT, API keys), webhook handlers, third-party API integration, rate limiting, retry logic, API versioning, error standardization, and OpenAPI documentation. Use when designing APIs, integrating external services, or building API clients.
npx skillsauth add RaheesAhmed/SajiCode api-architectInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
GET /api/v1/users → List users (paginated)
GET /api/v1/users/:id → Get single user
POST /api/v1/users → Create user
PATCH /api/v1/users/:id → Partial update user
DELETE /api/v1/users/:id → Delete user
GET /api/v1/users/:id/posts → List user's posts (nested resource)
// Success response
{ "data": { "id": "123", "name": "John" }, "meta": { "requestId": "req_abc" } }
// List response with pagination
{ "data": [...], "meta": { "total": 100, "page": 1, "perPage": 20, "totalPages": 5 } }
// Error response
{ "error": { "code": "VALIDATION_ERROR", "message": "Email is invalid", "details": [...] } }
| Code | Usage | |------|-------| | 200 | Success (GET, PATCH) | | 201 | Created (POST) | | 204 | No content (DELETE) | | 400 | Validation error | | 401 | Not authenticated | | 403 | Not authorized | | 404 | Resource not found | | 409 | Conflict (duplicate) | | 422 | Unprocessable entity | | 429 | Rate limited | | 500 | Server error |
// Login → returns access + refresh tokens
app.post("/api/auth/login", async (req, res) => {
const { email, password } = LoginSchema.parse(req.body);
const user = await userService.authenticate(email, password);
if (!user) return res.status(401).json({ error: { code: "INVALID_CREDENTIALS", message: "Invalid email or password" } });
const accessToken = jwt.sign({ sub: user.id, role: user.role }, JWT_SECRET, { expiresIn: "15m" });
const refreshToken = jwt.sign({ sub: user.id, type: "refresh" }, JWT_REFRESH_SECRET, { expiresIn: "7d" });
res.json({ data: { accessToken, refreshToken, user: { id: user.id, email: user.email } } });
});
// Auth middleware
function requireAuth(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) return res.status(401).json({ error: { code: "UNAUTHORIZED", message: "Token required" } });
try {
const payload = jwt.verify(token, JWT_SECRET) as { sub: string; role: string };
req.user = payload;
next();
} catch {
res.status(401).json({ error: { code: "TOKEN_EXPIRED", message: "Token expired" } });
}
}
function requireApiKey(req: Request, res: Response, next: NextFunction) {
const apiKey = req.headers["x-api-key"] as string;
if (!apiKey) return res.status(401).json({ error: { code: "API_KEY_REQUIRED", message: "x-api-key header required" } });
const client = await apiKeyService.validate(apiKey);
if (!client) return res.status(401).json({ error: { code: "INVALID_API_KEY", message: "Invalid API key" } });
req.client = client;
next();
}
import crypto from "crypto";
app.post("/api/webhooks/stripe", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["stripe-signature"] as string;
const payload = req.body;
// Verify webhook signature
const expectedSig = crypto.createHmac("sha256", WEBHOOK_SECRET).update(payload).digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSig))) {
return res.status(400).json({ error: { code: "INVALID_SIGNATURE" } });
}
const event = JSON.parse(payload.toString());
switch (event.type) {
case "checkout.session.completed":
handleCheckoutComplete(event.data.object);
break;
case "invoice.payment_failed":
handlePaymentFailed(event.data.object);
break;
}
res.json({ received: true });
});
class ApiClient {
private baseUrl: string;
private apiKey: string;
constructor(baseUrl: string, apiKey: string) {
this.baseUrl = baseUrl;
this.apiKey = apiKey;
}
private async request<T>(method: string, path: string, body?: unknown): Promise<T> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method,
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.apiKey}`,
},
body: body ? JSON.stringify(body) : undefined,
signal: controller.signal,
});
clearTimeout(timeout);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get("retry-after") || "5");
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
return this.request(method, path, body);
}
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new ApiError(`${method} ${path} failed: ${response.status}`, response.status, error);
}
return response.json() as Promise<T>;
} finally {
clearTimeout(timeout);
}
}
get<T>(path: string) { return this.request<T>("GET", path); }
post<T>(path: string, body: unknown) { return this.request<T>("POST", path, body); }
patch<T>(path: string, body: unknown) { return this.request<T>("PATCH", path, body); }
delete<T>(path: string) { return this.request<T>("DELETE", path); }
}
import rateLimit from "express-rate-limit";
// Tiered rate limiting
const publicLimiter = rateLimit({ windowMs: 60000, max: 30 });
const authenticatedLimiter = rateLimit({ windowMs: 60000, max: 100 });
const webhookLimiter = rateLimit({ windowMs: 60000, max: 500 });
app.use("/api/public", publicLimiter);
app.use("/api/v1", requireAuth, authenticatedLimiter);
app.use("/api/webhooks", webhookLimiter);
Option 1: URL versioning (recommended for REST)
/api/v1/users → /api/v2/users
Option 2: Header versioning
Accept: application/vnd.myapp.v2+json
Rules:
- Support previous version for minimum 6 months
- Document all breaking changes in changelog
- Use deprecation headers on old versions
origin: "*" in productiondevelopment
Create new agent skills with proper structure, progressive disclosure, and bundled resources. Use when user wants to create, write, or build a new skill.
development
Deep web research and data extraction skill. Systematically research ANY topic by fetching URLs, reading documentation, crawling API docs, evaluating npm/pypi packages, comparing technologies, and synthesizing findings into actionable recommendations. Use when researching libraries, frameworks, APIs, solutions, or any topic requiring web investigation.
development
Design and implement comprehensive test suites. Covers unit testing, integration testing, E2E testing with Playwright, API testing, mocking strategies, test data factories, TDD workflow, snapshot testing, coverage targets, and CI integration. Use when writing tests, designing test architecture, or debugging test failures.
development
Core engineering workflow that activates on EVERY task. Enforces systematic plan-before-code methodology, multi-file refactoring safety, dependency-aware changes, pre-flight verification, and zero-placeholder quality standards. Use PROACTIVELY on all coding tasks.