api-integration

Use when integrating Apidog + OpenAPI specifications with your React app. Covers MCP server setup, type generation, and query layer integration. Use when setting up API clients, generating types from OpenAPI, or integrating with Apidog MCP.

248 stars

Best use case

api-integration is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when integrating Apidog + OpenAPI specifications with your React app. Covers MCP server setup, type generation, and query layer integration. Use when setting up API clients, generating types from OpenAPI, or integrating with Apidog MCP.

Teams using api-integration 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

$curl -o ~/.claude/skills/api-integration/SKILL.md --create-dirs "https://raw.githubusercontent.com/MadAppGang/claude-code/main/plugins/frontend/skills/api-integration/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/api-integration/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How api-integration Compares

Feature / Agentapi-integrationStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when integrating Apidog + OpenAPI specifications with your React app. Covers MCP server setup, type generation, and query layer integration. Use when setting up API clients, generating types from OpenAPI, or integrating with Apidog MCP.

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.

Related Guides

SKILL.md Source

# 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()

  return useMutation({
    mutationFn: createUser,
    onSuccess: (newUser) => {
      // Add to cache
      queryClient.setQueryData(usersKeys.detail(newUser.id), newUser)

      // Invalidate list
      queryClient.invalidateQueries({ queryKey: usersKeys.lists() })
    },
  })
}
```

## Validation Strategy

**Always validate API responses:**

```typescript
import { z } from 'zod'

// Runtime validation
async function fetchUser(id: string): Promise<User> {
  const response = await apiClient.get(`/users/${id}`)

  try {
    return UserSchema.parse(response.data)
  } catch (error) {
    console.error('API response validation failed:', error)
    throw new Error('Invalid API response format')
  }
}
```

**Or use safe parse:**
```typescript
const result = UserSchema.safeParse(response.data)

if (!result.success) {
  console.error('Validation errors:', result.error.errors)
  throw new Error('Invalid user data')
}

return result.data
```

## Error Handling

**Global error handling:**
```typescript
import { QueryCache } from '@tanstack/react-query'

const queryCache = new QueryCache({
  onError: (error, query) => {
    if (axios.isAxiosError(error)) {
      if (error.response?.status === 404) {
        toast.error('Resource not found')
      } else if (error.response?.status === 500) {
        toast.error('Server error. Please try again.')
      }
    }
  },
})
```

## Best Practices

1. **Single Source of Truth** - OpenAPI spec via MCP is authoritative
2. **Validate Responses** - Use Zod schemas for runtime validation
3. **Encapsulation** - Keep all API details in `/src/api`
4. **Type Safety** - Export types from generated/hand-written schemas
5. **Error Handling** - Handle auth errors, network errors, validation errors
6. **Query Key Factories** - Hierarchical keys for flexible invalidation
7. **Feature-Based Organization** - Group queries/mutations by feature

## Workflow with AI Agent

1. **Agent reads latest OpenAPI spec** via Apidog MCP
2. **Agent generates or updates** types in `/src/api/types.ts`
3. **Agent implements queries** following established patterns
4. **Agent creates mutations** with proper invalidation
5. **Agent updates components** to use new API hooks

## Example: Full Feature Implementation

```typescript
// 1. Types (generated or hand-written)
// src/api/types.ts
export const TodoSchema = z.object({
  id: z.string(),
  text: z.string(),
  completed: z.boolean(),
})
export type Todo = z.infer<typeof TodoSchema>

// 2. Queries
// src/api/queries/todos.ts
export const todosKeys = {
  all: ['todos'] as const,
  lists: () => [...todosKeys.all, 'list'] as const,
}

export function todosQueryOptions() {
  return queryOptions({
    queryKey: todosKeys.lists(),
    queryFn: async () => {
      const response = await apiClient.get('/todos')
      return z.array(TodoSchema).parse(response.data)
    },
  })
}

// 3. Mutations
// src/api/mutations/todos.ts
export function useCreateTodo() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (text: string) => {
      const response = await apiClient.post('/todos', { text })
      return TodoSchema.parse(response.data)
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: todosKeys.lists() })
    },
  })
}

// 4. Component
// src/features/todos/TaskList.tsx
export function TaskList() {
  const { data: todos } = useQuery(todosQueryOptions())
  const createTodo = useCreateTodo()

  return (
    <div>
      {todos?.map(todo => <TodoItem key={todo.id} {...todo} />)}
      <AddTodoForm onSubmit={(text) => createTodo.mutate(text)} />
    </div>
  )
}
```

## Related Skills

- **tanstack-query** - Query and mutation patterns
- **tooling-setup** - TypeScript configuration for generated types
- **core-principles** - Project structure with `/src/api` directory

Related Skills

Claudish Integration Skill

248
from MadAppGang/claude-code

**Version:** 1.0.0

router-query-integration

248
from MadAppGang/claude-code

Use when setting up route loaders or optimizing navigation performance. Integrates TanStack Router with TanStack Query for optimal data fetching. Covers route loaders with query prefetching, ensuring instant navigation, and eliminating request waterfalls.

linear-integration

248
from MadAppGang/claude-code

Linear API patterns and examples for autopilot. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling.

test-skill

248
from MadAppGang/claude-code

A test skill for validation testing. Use when testing skill parsing and validation logic.

bad-skill

248
from MadAppGang/claude-code

This skill has invalid YAML in frontmatter

release

248
from MadAppGang/claude-code

Plugin release process for MAG Claude Plugins marketplace. Covers version bumping, marketplace.json updates, git tagging, and common mistakes. Use when releasing new plugin versions or troubleshooting update issues.

openrouter-trending-models

248
from MadAppGang/claude-code

Fetch trending programming models from OpenRouter rankings. Use when selecting models for multi-model review, updating model recommendations, or researching current AI coding trends. Provides model IDs, context windows, pricing, and usage statistics from the most recent week.

transcription

248
from MadAppGang/claude-code

Audio/video transcription using OpenAI Whisper. Covers installation, model selection, transcript formats (SRT, VTT, JSON), timing synchronization, and speaker diarization. Use when transcribing media or generating subtitles.

final-cut-pro

248
from MadAppGang/claude-code

Apple Final Cut Pro FCPXML format reference. Covers project structure, timeline creation, clip references, effects, and transitions. Use when generating FCP projects or understanding FCPXML structure.

ffmpeg-core

248
from MadAppGang/claude-code

FFmpeg fundamentals for video/audio manipulation. Covers common operations (trim, concat, convert, extract), codec selection, filter chains, and performance optimization. Use when planning or executing video processing tasks.

statusline-customization

248
from MadAppGang/claude-code

Configuration reference and troubleshooting for the statusline plugin — sections, themes, bar widths, and script architecture

technical-audit

248
from MadAppGang/claude-code

Technical SEO audit methodology including crawlability, indexability, and Core Web Vitals analysis. Use when auditing pages or sites for technical SEO issues.