adynato-web-api
Web API development conventions for Adynato projects. Covers API routes, middleware, authentication, error handling, validation, and response formats for Next.js and Node.js backends. Use when building or modifying API endpoints, server actions, or backend logic.
Best use case
adynato-web-api is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Web API development conventions for Adynato projects. Covers API routes, middleware, authentication, error handling, validation, and response formats for Next.js and Node.js backends. Use when building or modifying API endpoints, server actions, or backend logic.
Teams using adynato-web-api should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/adynato-web-api/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How adynato-web-api Compares
| Feature / Agent | adynato-web-api | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Web API development conventions for Adynato projects. Covers API routes, middleware, authentication, error handling, validation, and response formats for Next.js and Node.js backends. Use when building or modifying API endpoints, server actions, or backend logic.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Web API Skill
Use this skill when building APIs for Adynato web projects.
## Stack
- **Framework**: Next.js API Routes or App Router Route Handlers
- **Validation**: Zod
- **Auth**: NextAuth.js / Auth.js
- **Database**: Prisma + PostgreSQL
- **Rate Limiting**: Upstash
## Route Handlers (App Router)
### Basic Structure
```
app/
└── api/
├── auth/
│ └── [...nextauth]/
│ └── route.ts
├── users/
│ ├── route.ts # GET /api/users, POST /api/users
│ └── [id]/
│ └── route.ts # GET/PATCH/DELETE /api/users/:id
└── health/
└── route.ts
```
### Route Handler Pattern
```typescript
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { prisma } from '@/lib/prisma'
import { auth } from '@/lib/auth'
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
})
export async function GET(request: NextRequest) {
try {
const session = await auth()
if (!session) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
)
}
const users = await prisma.user.findMany({
select: { id: true, email: true, name: true },
})
return NextResponse.json({ data: users })
} catch (error) {
console.error('GET /api/users error:', error)
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
)
}
}
export async function POST(request: NextRequest) {
try {
const session = await auth()
if (!session) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
)
}
const body = await request.json()
const result = createUserSchema.safeParse(body)
if (!result.success) {
return NextResponse.json(
{ error: 'Validation failed', details: result.error.flatten() },
{ status: 400 }
)
}
const user = await prisma.user.create({
data: result.data,
})
return NextResponse.json({ data: user }, { status: 201 })
} catch (error) {
console.error('POST /api/users error:', error)
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
)
}
}
```
### Dynamic Route Handler
```typescript
// app/api/users/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
interface RouteParams {
params: { id: string }
}
export async function GET(request: NextRequest, { params }: RouteParams) {
const { id } = params
const user = await prisma.user.findUnique({
where: { id },
})
if (!user) {
return NextResponse.json(
{ error: 'User not found' },
{ status: 404 }
)
}
return NextResponse.json({ data: user })
}
export async function DELETE(request: NextRequest, { params }: RouteParams) {
const { id } = params
await prisma.user.delete({ where: { id } })
return new NextResponse(null, { status: 204 })
}
```
## Response Format
### Success Responses
```typescript
// Single resource
{ "data": { "id": "123", "name": "John" } }
// Collection
{ "data": [...], "meta": { "total": 100, "page": 1, "limit": 20 } }
// Created
{ "data": { ... } } // 201 status
// No content
// Empty body, 204 status
```
### Error Responses
```typescript
// Client error
{
"error": "Validation failed",
"details": { ... } // Optional
}
// Not found
{ "error": "Resource not found" }
// Unauthorized
{ "error": "Unauthorized" }
// Server error
{ "error": "Internal server error" }
```
## Validation with Zod
### Schema Definition
```typescript
// lib/validations/user.ts
import { z } from 'zod'
export const createUserSchema = z.object({
email: z.string().email('Invalid email address'),
name: z.string().min(1, 'Name is required').max(100),
role: z.enum(['user', 'admin']).default('user'),
})
export const updateUserSchema = createUserSchema.partial()
export type CreateUserInput = z.infer<typeof createUserSchema>
export type UpdateUserInput = z.infer<typeof updateUserSchema>
```
### Query Parameter Validation
```typescript
const querySchema = z.object({
page: z.coerce.number().min(1).default(1),
limit: z.coerce.number().min(1).max(100).default(20),
search: z.string().optional(),
})
export async function GET(request: NextRequest) {
const searchParams = Object.fromEntries(request.nextUrl.searchParams)
const query = querySchema.parse(searchParams)
// ...
}
```
## Authentication
### Auth Check Helper
```typescript
// lib/auth.ts
import { getServerSession } from 'next-auth'
import { authOptions } from '@/app/api/auth/[...nextauth]/route'
export async function auth() {
return getServerSession(authOptions)
}
export async function requireAuth() {
const session = await auth()
if (!session) {
throw new Error('Unauthorized')
}
return session
}
```
### Protected Route Pattern
```typescript
export async function GET(request: NextRequest) {
const session = await auth()
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// Proceed with authenticated logic
}
```
## Server Actions
For mutations that don't need to be APIs:
```typescript
// app/actions/user.ts
'use server'
import { z } from 'zod'
import { revalidatePath } from 'next/cache'
import { prisma } from '@/lib/prisma'
import { auth } from '@/lib/auth'
const updateProfileSchema = z.object({
name: z.string().min(1).max(100),
})
export async function updateProfile(formData: FormData) {
const session = await auth()
if (!session?.user?.id) {
throw new Error('Unauthorized')
}
const result = updateProfileSchema.safeParse({
name: formData.get('name'),
})
if (!result.success) {
return { error: result.error.flatten() }
}
await prisma.user.update({
where: { id: session.user.id },
data: result.data,
})
revalidatePath('/profile')
return { success: true }
}
```
## Rate Limiting
```typescript
// lib/rate-limit.ts
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'),
})
export async function checkRateLimit(identifier: string) {
const { success, limit, remaining } = await ratelimit.limit(identifier)
return { success, limit, remaining }
}
```
```typescript
// In route handler
export async function POST(request: NextRequest) {
const ip = request.ip ?? 'anonymous'
const { success } = await checkRateLimit(ip)
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429 }
)
}
// ...
}
```
## Error Handling
### Global Error Handler
```typescript
// lib/api-error.ts
export class ApiError extends Error {
constructor(
public statusCode: number,
message: string,
public details?: unknown
) {
super(message)
}
}
export function handleApiError(error: unknown) {
console.error('API Error:', error)
if (error instanceof ApiError) {
return NextResponse.json(
{ error: error.message, details: error.details },
{ status: error.statusCode }
)
}
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation failed', details: error.flatten() },
{ status: 400 }
)
}
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
)
}
```
## Checklist
Before deploying APIs:
- [ ] All inputs validated with Zod
- [ ] Authentication checked on protected routes
- [ ] Rate limiting on public endpoints
- [ ] Proper error responses with correct status codes
- [ ] No sensitive data leaked in responses
- [ ] Logging for errors (not sensitive data)
- [ ] CORS configured if needed
- [ ] Response times acceptableRelated Skills
adynato-aimake
Integrate with aimake's AI-powered delivery pipeline via MCP. Covers connecting to aimake, using code/docs/kanban tools, understanding the card-based system, and leveraging AI capabilities. Use when building integrations with aimake or using its MCP tools.
adynato-github
GitHub workflow conventions for Adynato projects. Covers creating PRs with gh CLI, writing thorough descriptions, and using stacked PRs for large deliverables. Use when creating pull requests, managing branches, or breaking down large features.
adynato-seo
Handles SEO requirements for all web content including blogs, landing pages, and documentation. Covers LD+JSON schema.org structured data, internal backlinks strategy, further reading sections, meta tags, and Open Graph. Use when creating or editing any public-facing web content, blog posts, or pages that need search visibility.
adynato-mobile-api
API integration patterns for Adynato mobile apps. Covers data fetching with TanStack Query, authentication flows, offline support, error handling, and optimistic updates in React Native/Expo apps. Use when integrating APIs into mobile applications.
bgo
Automates the complete Blender build-go workflow, from building and packaging your extension/add-on to removing old versions, installing, enabling, and launching Blender for quick testing and iteration.
obsidian-daily
Manage Obsidian Daily Notes via obsidian-cli. Create and open daily notes, append entries (journals, logs, tasks, links), read past notes by date, and search vault content. Handles relative dates like "yesterday", "last Friday", "3 days ago".
obsidian-additions
Create supplementary materials attached to existing notes: experiments, meetings, reports, logs, conspectuses, practice sessions, annotations, AI outputs, links collections. Two-step process: (1) create aggregator space, (2) create concrete addition in base/additions/. INVOKE when user wants to attach any supplementary material to an existing note. Triggers: "addition", "create addition", "experiment", "meeting notes", "report", "conspectus", "log", "practice", "annotations", "links", "link collection", "аддишн", "конспект", "встреча", "отчёт", "эксперимент", "практика", "аннотации", "ссылки", "добавь к заметке".
observe
Query and manage Observe using the Observe CLI. Use when the user wants to run OPAL queries, list datasets, manage objects, or interact with their Observe tenant from the command line.
observability-review
AI agent that analyzes operational signals (metrics, logs, traces, alerts, SLO/SLI reports) from observability platforms (Prometheus, Datadog, New Relic, CloudWatch, Grafana, Elastic) and produces practical, risk-aware triage and recommendations. Use when reviewing system health, investigating performance issues, analyzing monitoring data, evaluating service reliability, or providing SRE analysis of operational metrics. Distinguishes between critical issues requiring action, items needing investigation, and informational observations requiring no action.
nvidia-nim
NVIDIA NIM inference microservices for deploying AI models with OpenAI-compatible APIs, self-hosted or cloud
numpy-string-ops
Vectorized string manipulation using the char module and modern string alternatives, including cleaning and search operations. Triggers: string operations, numpy.char, text cleaning, substring search.
nova-act-usability
AI-orchestrated usability testing using Amazon Nova Act. The agent generates personas, runs tests to collect raw data, interprets responses to determine goal achievement, and generates HTML reports. Tests real user workflows (booking, checkout, posting) with safety guardrails. Use when asked to "test website usability", "run usability test", "generate usability report", "evaluate user experience", "test checkout flow", "test booking process", or "analyze website UX".