Use when creating OpenAPI specs for Bun.js APIs, integrating with Apidog, documenting endpoints with schemas, or automating API specification imports via Apidog REST API. See bunjs for basics.
bunjs-apidog follows the SKILL.md standard. Use the install command to add it to your agent stack.
---
name: bunjs-apidog
version: 1.0.0
description: Use when creating OpenAPI specs for Bun.js APIs, integrating with Apidog, documenting endpoints with schemas, or automating API specification imports via Apidog REST API. See bunjs for basics.
keywords:
- OpenAPI
- Apidog
- API documentation
- Swagger
- API specs
- integration
- API design
plugin: dev
updated: 2026-01-20
---
# Bun.js OpenAPI and Apidog Integration
## Overview
This skill covers OpenAPI specification creation and Apidog integration for Bun.js TypeScript backend applications. Learn how to document APIs with OpenAPI 3.0, use Apidog-specific extensions, import specifications via REST API, and maintain synchronized API documentation.
**When to use this skill:**
- Creating OpenAPI specifications for API documentation
- Synchronizing API specs with Apidog projects
- Importing endpoints and schemas to Apidog
- Managing API documentation lifecycle
**See also:**
- **dev:bunjs** - Core Bun patterns, HTTP servers, database access
- **dev:bunjs-architecture** - Layered architecture, camelCase conventions
- **dev:bunjs-production** - Production deployment patterns
## Why Apidog
Apidog is a comprehensive API development platform that combines:
- **API Design** - Visual OpenAPI editor
- **API Documentation** - Auto-generated, always up-to-date docs
- **API Testing** - Built-in testing tools
- **API Mocking** - Mock servers for frontend development
- **Team Collaboration** - Shared workspace for teams
## Environment Variables
**Required:**
```bash
APIDOG_PROJECT_ID=your-project-id # From Apidog project settings
APIDOG_API_TOKEN=your-api-token # From Apidog account settings
```
**How to get these:**
1. **APIDOG_PROJECT_ID**: Open your Apidog project → Settings → Project ID
2. **APIDOG_API_TOKEN**: Apidog Account → Settings → API Tokens → Generate Token
## OpenAPI Spec Creation
### Basic Structure
```yaml
openapi: 3.0.0
info:
title: My API
version: 1.0.0
description: API for managing resources
servers:
- url: https://api.example.com/v1
description: Production server
- url: https://staging-api.example.com/v1
description: Staging server
- url: http://localhost:3000
description: Development server
components:
schemas:
# Define reusable data models here
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
paths:
# Define API endpoints here
```
### Field Naming: camelCase (CRITICAL)
**ALWAYS use camelCase for all JSON API field names in OpenAPI specs.**
```yaml
components:
schemas:
User:
type: object
required:
- userId
- emailAddress
properties:
userId: # ✅ camelCase
type: string
format: uuid
emailAddress: # ✅ camelCase
type: string
format: email
firstName: # ✅ camelCase
type: string
lastName: # ✅ camelCase
type: string
phoneNumber: # ✅ camelCase
type: string
isActive: # ✅ camelCase boolean
type: boolean
createdAt: # ✅ camelCase timestamp
type: string
format: date-time
updatedAt: # ✅ camelCase timestamp
type: string
format: date-time
# ❌ WRONG: snake_case
# user_id, email_address, first_name, created_at
# ❌ WRONG: PascalCase
# UserId, EmailAddress, FirstName, CreatedAt
```
**Why camelCase:**
- Native to JavaScript/JSON ecosystem
- Industry standard (Google, Microsoft, AWS)
- TypeScript friendly (1:1 mapping)
- OpenAPI/Swagger convention
- Auto-generated clients expect it
### Schema Design
**Define reusable schemas in `components.schemas`:**
```yaml
components:
schemas:
User:
type: object
required:
- userId
- emailAddress
- firstName
- lastName
properties:
userId:
type: string
format: uuid
description: Unique user identifier
emailAddress:
type: string
format: email
description: User email address
firstName:
type: string
minLength: 2
maxLength: 100
lastName:
type: string
minLength: 2
maxLength: 100
phoneNumber:
type: string
pattern: '^\+?[1-9]\d{1,14}$'
role:
type: string
enum: [user, admin, moderator]
default: user
isActive:
type: boolean
default: true
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
CreateUserRequest:
type: object
required:
- emailAddress
- password
- firstName
- lastName
properties:
emailAddress:
type: string
format: email
password:
type: string
format: password
minLength: 8
firstName:
type: string
minLength: 2
lastName:
type: string
minLength: 2
phoneNumber:
type: string
role:
type: string
enum: [user, admin, moderator]
UserListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/Pagination'
Pagination:
type: object
properties:
page:
type: integer
minimum: 1
pageSize:
type: integer
minimum: 1
maximum: 100
total:
type: integer
totalPages:
type: integer
ErrorResponse:
type: object
properties:
statusCode:
type: integer
type:
type: string
message:
type: string
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
```
### Endpoint Definitions
**Define endpoints in `paths`:**
```yaml
paths:
/users:
get:
summary: List users
description: Retrieve paginated list of users
operationId: listUsers
tags:
- Users
security:
- bearerAuth: []
x-apidog-folder: User Management/Users
x-apidog-status: released
x-apidog-maintainer: backend-team
parameters:
- name: page
in: query
schema:
type: integer
minimum: 1
default: 1
- name: pageSize
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
- name: sortBy
in: query
schema:
type: string
enum: [createdAt, firstName, emailAddress]
- name: orderBy
in: query
schema:
type: string
enum: [asc, desc]
default: desc
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/UserListResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
post:
summary: Create user
description: Create a new user account
operationId: createUser
tags:
- Users
x-apidog-folder: User Management/Users
x-apidog-status: released
x-apidog-maintainer: backend-team
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: User created successfully
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/User'
'400':
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: User already exists
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'422':
description: Validation failed
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/users/{userId}:
get:
summary: Get user
description: Retrieve a single user by ID
operationId: getUser
tags:
- Users
security:
- bearerAuth: []
x-apidog-folder: User Management/Users
x-apidog-status: released
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/User'
'404':
description: User not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
```
## Apidog-Specific Extensions
### x-apidog-folder
Organize endpoints in folders using `/` to separate levels:
```yaml
paths:
/users:
post:
x-apidog-folder: User Management/Users
/users/{userId}/profile:
get:
x-apidog-folder: User Management/Users/Profile
/orders:
post:
x-apidog-folder: Order Management/Orders
```
**Escaping special characters:**
- Use `\/` for `/`
- Use `\\` for `\`
### x-apidog-status
Endpoint lifecycle status:
| Status | Description |
|--------|-------------|
| `designing` | Being designed |
| `pending` | Pending implementation |
| `developing` | In development |
| `integrating` | Integration phase |
| `testing` | Being tested |
| `tested` | Testing complete |
| `released` | Production release |
| `deprecated` | Marked for deprecation |
| `exception` | Has issues |
| `obsolete` | No longer used |
| `to be deprecated` | Will be deprecated |
```yaml
paths:
/users:
post:
x-apidog-status: released # Fully implemented
/beta/feature:
post:
x-apidog-status: testing # In testing phase
/legacy/api:
get:
x-apidog-status: deprecated # Being phased out
```
### x-apidog-maintainer
Specify owner/maintainer (use Apidog username or nickname):
```yaml
paths:
/users:
post:
x-apidog-maintainer: backend-team
/admin/settings:
put:
x-apidog-maintainer: john-doe
```
## Importing to Apidog via REST API
### Import Process
**Step 1: Prepare OpenAPI Spec**
Create a complete OpenAPI 3.0 spec in JSON format:
```bash
# Save spec to file
cat > /tmp/api-spec.json << 'EOF'
{
"openapi": "3.0.0",
"info": { ... },
"paths": { ... }
}
EOF
```
**Step 2: Import via REST API**
```bash
#!/bin/bash
# Environment variables (from .env)
APIDOG_PROJECT_ID="your-project-id"
APIDOG_API_TOKEN="your-api-token"
# Read OpenAPI spec
OPENAPI_SPEC=$(cat /tmp/api-spec.json | jq -c .)
# Import to Apidog
curl -X POST "https://api.apidog.com/v1/projects/${APIDOG_PROJECT_ID}/import-openapi" \
-H "Authorization: Bearer ${APIDOG_API_TOKEN}" \
-H "X-Apidog-Api-Version: 2024-03-28" \
-H "Content-Type: application/json" \
-d "{
\"input\": \"${OPENAPI_SPEC}\",
\"options\": {
\"endpointOverwriteBehavior\": \"AUTO_MERGE\",
\"schemaOverwriteBehavior\": \"AUTO_MERGE\",
\"updateFolderOfChangedEndpoint\": false,
\"prependBasePath\": false
}
}"
```
### Import Behavior Options
| Option | Description |
|--------|-------------|
| `AUTO_MERGE` | Automatically merge changes (recommended) |
| `OVERWRITE_EXISTING` | Replace existing endpoints/schemas completely |
| `KEEP_EXISTING` | Skip changes, keep existing |
| `CREATE_NEW` | Create new endpoints/schemas (duplicates existing) |
**Recommendation: Use `AUTO_MERGE`** for intelligent merging without losing existing data.
### API Response Format
```json
{
"data": {
"counters": {
"endpointCreated": 3,
"endpointUpdated": 2,
"endpointFailed": 0,
"endpointIgnored": 0,
"schemaCreated": 5,
"schemaUpdated": 1,
"schemaFailed": 0,
"schemaIgnored": 0,
"endpointFolderCreated": 1,
"endpointFolderUpdated": 0,
"schemaFolderCreated": 0,
"schemaFolderUpdated": 0
},
"errors": []
}
}
```
### Error Handling
| Status Code | Meaning |
|-------------|---------|
| 401 | Token is invalid or expired |
| 404 | Project ID not found |
| 422 | OpenAPI spec validation failed |
**Check `data.errors` array for detailed error messages.**
## Workflow
### 1. Create OpenAPI Spec from Code
**Step 1: Analyze existing endpoints**
```bash
# List all route files
find src/routes -name "*.ts" -type f
# Read route definitions
cat src/routes/user.routes.ts
```
**Step 2: Extract schemas from Zod**
```typescript
// src/schemas/user.schema.ts
import { z } from 'zod';
export const createUserSchema = z.object({
emailAddress: z.string().email(),
password: z.string().min(8),
firstName: z.string(),
lastName: z.string()
});
// Convert to OpenAPI schema manually or use zod-to-json-schema
```
**Step 3: Build OpenAPI spec**
Map routes to OpenAPI paths, schemas to components, camelCase fields.
### 2. Validate Spec
```bash
# Use online validator
# https://editor.swagger.io/
# Or use CLI tool
npm install -g swagger-cli
swagger-cli validate api-spec.yaml
```
### 3. Import to Apidog
```bash
# Via REST API (automated)
./scripts/import-to-apidog.sh
# Or manually in Apidog UI
# Import → OpenAPI → Upload file
```
### 4. Verify in Apidog
1. Open Apidog project: `https://app.apidog.com/project/{APIDOG_PROJECT_ID}`
2. Check imported endpoints appear in correct folders
3. Verify schemas are properly structured
4. Test endpoints with Apidog's testing tools
5. Update descriptions and add examples
### 5. Set Endpoint Status
Update `x-apidog-status` based on implementation progress:
- `designing` → `developing` → `testing` → `released`
### 6. Share with Team
Share Apidog project with team members for:
- Frontend integration (use mock servers)
- API testing
- Documentation review
## Automation Script
**scripts/import-to-apidog.sh:**
```bash
#!/bin/bash
set -e
# Load environment variables
source .env
# Check required variables
if [ -z "$APIDOG_PROJECT_ID" ] || [ -z "$APIDOG_API_TOKEN" ]; then
echo "Error: APIDOG_PROJECT_ID and APIDOG_API_TOKEN must be set"
exit 1
fi
# Generate OpenAPI spec (customize based on your needs)
SPEC_FILE="/tmp/api-spec-$(date +%Y%m%d-%H%M%S).json"
echo "Generating OpenAPI spec..."
# Add your spec generation logic here
# For example: ts-node scripts/generate-openapi.ts > $SPEC_FILE
# Read spec
OPENAPI_SPEC=$(cat $SPEC_FILE | jq -c .)
# Import to Apidog
echo "Importing to Apidog..."
RESPONSE=$(curl -s -X POST \
"https://api.apidog.com/v1/projects/${APIDOG_PROJECT_ID}/import-openapi" \
-H "Authorization: Bearer ${APIDOG_API_TOKEN}" \
-H "X-Apidog-Api-Version: 2024-03-28" \
-H "Content-Type: application/json" \
-d "{
\"input\": ${OPENAPI_SPEC},
\"options\": {
\"endpointOverwriteBehavior\": \"AUTO_MERGE\",
\"schemaOverwriteBehavior\": \"AUTO_MERGE\"
}
}")
# Parse response
ENDPOINT_CREATED=$(echo $RESPONSE | jq -r '.data.counters.endpointCreated')
ENDPOINT_UPDATED=$(echo $RESPONSE | jq -r '.data.counters.endpointUpdated')
SCHEMA_CREATED=$(echo $RESPONSE | jq -r '.data.counters.schemaCreated')
SCHEMA_UPDATED=$(echo $RESPONSE | jq -r '.data.counters.schemaUpdated')
ERRORS=$(echo $RESPONSE | jq -r '.data.errors | length')
# Display summary
echo ""
echo "✅ Import Complete!"
echo ""
echo "Endpoints:"
echo " Created: $ENDPOINT_CREATED"
echo " Updated: $ENDPOINT_UPDATED"
echo ""
echo "Schemas:"
echo " Created: $SCHEMA_CREATED"
echo " Updated: $SCHEMA_UPDATED"
echo ""
echo "Errors: $ERRORS"
echo ""
echo "🔗 View in Apidog: https://app.apidog.com/project/${APIDOG_PROJECT_ID}"
# Exit with error if there were errors
if [ "$ERRORS" != "0" ]; then
echo ""
echo "⚠️ Import had errors. Check response:"
echo $RESPONSE | jq '.data.errors'
exit 1
fi
```
## Error Scenarios & Solutions
### Missing Environment Variables
**Problem:** `APIDOG_PROJECT_ID` or `APIDOG_API_TOKEN` not set
**Solution:**
```bash
# Add to .env file
APIDOG_PROJECT_ID=your-project-id
APIDOG_API_TOKEN=your-api-token
# Restart application
```
### Schema Conflicts
**Problem:** New schema conflicts with existing schema
**Solution:**
- Use `allOf` to extend existing schemas
- Or create with different name
- Or use `OVERWRITE_EXISTING` behavior (carefully)
### Import Failures
**Problem:** Automated import fails
**Solution:**
- Check API token validity
- Verify project ID
- Validate OpenAPI spec syntax
- Check `data.errors` in response for details
### Invalid OpenAPI Spec
**Problem:** Generated spec has validation errors
**Solution:**
```bash
# Validate before importing
swagger-cli validate api-spec.yaml
# Fix validation errors
# Common issues:
# - Missing required fields
# - Invalid $ref paths
# - Incorrect enum values
# - Wrong data types
```
## Best Practices
### 1. Schema Reuse
```yaml
# ✅ CORRECT: Reuse schemas with $ref
paths:
/users/{userId}:
get:
responses:
'200':
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/User'
# ❌ WRONG: Duplicate schema definitions
paths:
/users/{userId}:
get:
responses:
'200':
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
userId: { type: string }
# ... duplicated fields
```
### 2. Comprehensive Descriptions
```yaml
# ✅ CORRECT: Clear descriptions
paths:
/users:
post:
summary: Create user
description: |
Creates a new user account with email verification.
The password must meet the following requirements:
- At least 8 characters
- Contains uppercase and lowercase letters
- Contains at least one number
- Contains at least one special character
Upon successful creation, a verification email is sent to the provided email address.
```
### 3. Response Examples
```yaml
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/User'
example:
data:
userId: "550e8400-e29b-41d4-a716-446655440000"
emailAddress: "john@example.com"
firstName: "John"
lastName: "Doe"
isActive: true
createdAt: "2025-01-06T12:00:00Z"
```
### 4. Security Schemes
```yaml
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT access token obtained from /auth/login
# Apply globally
security:
- bearerAuth: []
# Or per endpoint
paths:
/public/health:
get:
security: [] # No auth required
```
### 5. Version Your API
```yaml
servers:
- url: https://api.example.com/v1
description: Version 1 (current)
- url: https://api.example.com/v2
description: Version 2 (beta)
```
---
*OpenAPI and Apidog integration for Bun.js TypeScript backend. For core patterns, see dev:bunjs. For architecture, see dev:bunjs-architecture.*