api-integration
This Claude Code skill configures an MCP server to expose OpenAPI specifications from Apidog, enabling AI agents to generate TypeScript types and TanStack Query hooks directly from your API documentation. Use it when setting up API clients, generating frontend types from OpenAPI schemas, or integrating multiple backend APIs into React applications through a single source of truth.
git clone --depth 1 https://github.com/MadAppGang/claude-code /tmp/api-integration && cp -r /tmp/api-integration/plugins/frontend/skills/api-integration ~/.claude/skills/api-integrationSKILL.md
# API Integration (Apidog + MCP)
Integrate OpenAPI specifications with your frontend using Apidog MCP for single source of truth.
## Goal
The AI agent always uses the latest API specification to generate types and implement features correctly.
## Architecture
```
Apidog (or Backend)
→ OpenAPI 3.0/3.1 Spec
→ MCP Server (apidog-mcp-server)
→ AI Agent reads spec
→ Generate TypeScript types
→ TanStack Query hooks
→ React Components
```
## Process
### 1. Expose OpenAPI from Apidog
**Option A: Remote URL**
- Export OpenAPI spec from Apidog
- Host at a URL (e.g., `https://api.example.com/openapi.json`)
**Option B: Local File**
- Export OpenAPI spec to file
- Place in project (e.g., `./api-spec/openapi.json`)
### 2. Wire MCP Server
```json
// .claude/mcp.json or settings
{
"mcpServers": {
"API specification": {
"command": "npx",
"args": [
"-y",
"apidog-mcp-server@latest",
"--oas=https://api.example.com/openapi.json"
]
}
}
}
```
**With Local File:**
```json
{
"mcpServers": {
"API specification": {
"command": "npx",
"args": [
"-y",
"apidog-mcp-server@latest",
"--oas=./api-spec/openapi.json"
]
}
}
}
```
**Multiple APIs:**
```json
{
"mcpServers": {
"Main API": {
"command": "npx",
"args": ["-y", "apidog-mcp-server@latest", "--oas=https://api.main.com/openapi.json"]
},
"Auth API": {
"command": "npx",
"args": ["-y", "apidog-mcp-server@latest", "--oas=https://api.auth.com/openapi.json"]
}
}
}
```
### 3. Generate Types & Client
Create `/src/api` directory for all API-related code:
```
/src/api/
├── types.ts # Generated from OpenAPI
├── client.ts # HTTP client (axios/fetch)
├── queries/ # TanStack Query hooks
│ ├── users.ts
│ ├── posts.ts
│ └── ...
└── mutations/ # TanStack Mutation hooks
├── users.ts
├── posts.ts
└── ...
```
**Option A: Hand-Written Types (Lightweight)**
```typescript
// src/api/types.ts
import { z } from 'zod'
// Define schemas from OpenAPI
export const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
createdAt: z.string().datetime(),
})
export type User = z.infer<typeof UserSchema>
export const CreateUserSchema = UserSchema.omit({ id: true, createdAt: true })
export type CreateUserDTO = z.infer<typeof CreateUserSchema>
```
**Option B: Code Generation (Recommended for large APIs)**
```bash
# Using openapi-typescript
pnpm add -D openapi-typescript
npx openapi-typescript https://api.example.com/openapi.json -o src/api/types.ts
# Using orval
pnpm add -D orval
npx orval --input https://api.example.com/openapi.json --output src/api
```
### 4. Create HTTP Client
```typescript
// src/api/client.ts
import axios from 'axios'
import createAuthRefreshInterceptor from 'axios-auth-refresh'
export const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_URL,
headers: {
'Content-Type': 'application/json',
},
})
// Request interceptor - add auth token
apiClient.interceptors.request.use((config) => {
const token = localStorage.getItem('accessToken')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// Response interceptor - handle token refresh
const refreshAuth = async (failedRequest: any) => {
try {
const refreshToken = localStorage.getItem('refreshToken')
const response = await axios.post('/auth/refresh', { refreshToken })
const { accessToken } = response.data
localStorage.setItem('accessToken', accessToken)
failedRequest.response.config.headers.Authorization = `Bearer ${accessToken}`
return Promise.resolve()
} catch (error) {
localStorage.removeItem('accessToken')
localStorage.removeItem('refreshToken')
window.location.href = '/login'
return Promise.reject(error)
}
}
createAuthRefreshInterceptor(apiClient, refreshAuth, {
statusCodes: [401],
pauseInstanceWhileRefreshing: true,
})
```
### 5. Build Query Layer
**Feature-based query organization:**
```typescript
// src/api/queries/users.ts
import { queryOptions } from '@tanstack/react-query'
import { apiClient } from '../client'
import { User, UserSchema } from '../types'
// Query key factory
export const usersKeys = {
all: ['users'] as const,
lists: () => [...usersKeys.all, 'list'] as const,
list: (filters: string) => [...usersKeys.lists(), { filters }] as const,
details: () => [...usersKeys.all, 'detail'] as const,
detail: (id: string) => [...usersKeys.details(), id] as const,
}
// API functions
async function fetchUsers(): Promise<User[]> {
const response = await apiClient.get('/users')
return z.array(UserSchema).parse(response.data)
}
async function fetchUser(id: string): Promise<User> {
const response = await apiClient.get(`/users/${id}`)
return UserSchema.parse(response.data)
}
// Query options
export function usersListQueryOptions() {
return queryOptions({
queryKey: usersKeys.lists(),
queryFn: fetchUsers,
staleTime: 30_000,
})
}
export function userQueryOptions(id: string) {
return queryOptions({
queryKey: usersKeys.detail(id),
queryFn: () => fetchUser(id),
staleTime: 60_000,
})
}
// Hooks
export function useUsers() {
return useQuery(usersListQueryOptions())
}
export function useUser(id: string) {
return useQuery(userQueryOptions(id))
}
```
**Mutations:**
```typescript
// src/api/mutations/users.ts
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { apiClient } from '../client'
import { CreateUserDTO, User, UserSchema } from '../types'
import { usersKeys } from '../queries/users'
async function createUser(data: CreateUserDTO): Promise<User> {
const response = await apiClient.post('/users', data)
return UserSchema.parse(response.data)
}
export function useCreateUser() {
const queryClient = useQueryClient()Architecture Decision Records (ADR) documentation practice. Use when documenting architectural decisions, recording technical trade-offs, creating decision logs, or establishing architectural patterns. Trigger keywords - "ADR", "architecture decision", "decision record", "trade-offs", "architectural decision", "decision log".
Use when deciding whether to launch an agent, selecting which agent to use, or coordinating multiple agents. Covers delegation criteria, external-model patterns, task isolation, and agent selection strategies.
Use when designing REST or GraphQL APIs, defining endpoints, implementing pagination/filtering, handling API versioning, or establishing API documentation with OpenAPI/Swagger.
Analyzes API documentation from OpenAPI specs to provide TypeScript interfaces, request/response formats, and implementation guidance. Use when implementing API integrations, debugging API errors (400, 401, 404), replacing mock APIs, verifying data types, or when user mentions endpoints, API calls, or backend integration.
Use when analyzing architecture and system design. Find design patterns, map layers, identify core abstractions via PageRank. Uses claudemem AST structural analysis for efficient architecture investigation.
On-demand security and code quality audit. Use when checking for vulnerabilities, security issues, code smells, or compliance problems. Trigger keywords - "audit", "security check", "vulnerability scan", "code quality", "compliance", "security audit".
Use when implementing authentication (JWT, sessions, OAuth), authorization (RBAC, ABAC), password hashing, MFA, or security best practices for backend services.
Collaborative ideation and planning with resilient multi-model exploration, consensus scoring, and adaptive confidence-based validation