Quick API endpoint testing with comprehensive request/response validation.
Tests API endpoints with comprehensive request/response validation, authentication checks, and schema verification. Use it when you need to validate REST, GraphQL, or other APIs with curl commands, automated test scripts, or Postman collections.
/plugin marketplace add CuriousLearner/devkit/plugin install devkit@devkit-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Quick API endpoint testing with comprehensive request/response validation.
You are an API testing expert. When invoked:
Test API Endpoints:
Generate Test Cases:
Performance Testing:
Security Testing:
@api-tester
@api-tester --endpoint /api/users
@api-tester --method POST
@api-tester --load-test
@api-tester --generate-collection
# curl
curl -X GET https://api.example.com/api/users \
-H "Content-Type: application/json"
# With authentication
curl -X GET https://api.example.com/api/users \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json"
# With query parameters
curl -X GET "https://api.example.com/api/users?page=1&limit=10&sort=created_at" \
-H "Authorization: Bearer YOUR_TOKEN"
# Verbose output (includes headers)
curl -v -X GET https://api.example.com/api/users
// Using fetch
async function getUsers() {
const response = await fetch('https://api.example.com/api/users', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
}
// Using axios
const axios = require('axios');
async function getUsers() {
try {
const response = await axios.get('https://api.example.com/api/users', {
headers: {
'Authorization': 'Bearer YOUR_TOKEN'
},
params: {
page: 1,
limit: 10
}
});
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
throw error;
}
}
import requests
# Basic GET request
response = requests.get('https://api.example.com/api/users')
print(response.json())
# With authentication and parameters
headers = {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
}
params = {
'page': 1,
'limit': 10,
'sort': 'created_at'
}
response = requests.get(
'https://api.example.com/api/users',
headers=headers,
params=params
)
if response.status_code == 200:
data = response.json()
print(data)
else:
print(f"Error: {response.status_code}")
print(response.text)
# curl
curl -X POST https://api.example.com/api/users \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"role": "user"
}'
# From file
curl -X POST https://api.example.com/api/users \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d @user.json
// Using fetch
async function createUser(userData) {
const response = await fetch('https://api.example.com/api/users', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
});
const data = await response.json();
return data;
}
// Usage
const newUser = {
name: 'John Doe',
email: 'john@example.com',
role: 'user'
};
createUser(newUser)
.then(user => console.log('Created:', user))
.catch(error => console.error('Error:', error));
// Using axios with error handling
async function createUser(userData) {
try {
const response = await axios.post(
'https://api.example.com/api/users',
userData,
{
headers: {
'Authorization': 'Bearer YOUR_TOKEN'
}
}
);
return response.data;
} catch (error) {
if (error.response) {
// Server responded with error
console.error('Error:', error.response.status);
console.error('Message:', error.response.data);
} else if (error.request) {
// No response received
console.error('No response from server');
} else {
console.error('Error:', error.message);
}
throw error;
}
}
import requests
# Create user
user_data = {
'name': 'John Doe',
'email': 'john@example.com',
'role': 'user'
}
headers = {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
}
response = requests.post(
'https://api.example.com/api/users',
json=user_data,
headers=headers
)
if response.status_code == 201:
print('User created:', response.json())
else:
print(f'Error: {response.status_code}')
print(response.json())
# PUT - Replace entire resource
curl -X PUT https://api.example.com/api/users/123 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "John Updated",
"email": "john.updated@example.com",
"role": "admin"
}'
# PATCH - Partial update
curl -X PATCH https://api.example.com/api/users/123 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"role": "admin"
}'
# Delete resource
curl -X DELETE https://api.example.com/api/users/123 \
-H "Authorization: Bearer YOUR_TOKEN"
# Delete with confirmation
curl -X DELETE https://api.example.com/api/users/123 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Confirm-Delete: true"
# Get token
curl -X POST https://api.example.com/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "password123"
}'
# Use token
curl -X GET https://api.example.com/api/users \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# In header
curl -X GET https://api.example.com/api/users \
-H "X-API-Key: your-api-key-here"
# In query parameter
curl -X GET "https://api.example.com/api/users?api_key=your-api-key-here"
# Username and password
curl -X GET https://api.example.com/api/users \
-u username:password
# Base64 encoded
curl -X GET https://api.example.com/api/users \
-H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ="
// Get access token
async function getAccessToken() {
const response = await fetch('https://oauth.example.com/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET'
})
});
const data = await response.json();
return data.access_token;
}
// Use access token
async function callAPI() {
const token = await getAccessToken();
const response = await fetch('https://api.example.com/api/users', {
headers: {
'Authorization': `Bearer ${token}`
}
});
return response.json();
}
# curl
curl -X POST https://api.example.com/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "{ users { id name email } }"
}'
# With variables
curl -X POST https://api.example.com/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "query GetUser($id: ID!) { user(id: $id) { id name email } }",
"variables": { "id": "123" }
}'
// Create user mutation
async function createUser(name, email) {
const query = `
mutation CreateUser($name: String!, $email: String!) {
createUser(input: { name: $name, email: $email }) {
id
name
email
createdAt
}
}
`;
const response = await fetch('https://api.example.com/graphql', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query,
variables: { name, email }
})
});
const data = await response.json();
return data.data.createUser;
}
const axios = require('axios');
describe('User API Tests', () => {
const API_URL = 'https://api.example.com';
const token = 'YOUR_TEST_TOKEN';
const api = axios.create({
baseURL: API_URL,
headers: {
'Authorization': `Bearer ${token}`
}
});
describe('GET /api/users', () => {
test('should return list of users', async () => {
const response = await api.get('/api/users');
expect(response.status).toBe(200);
expect(Array.isArray(response.data)).toBe(true);
expect(response.data.length).toBeGreaterThan(0);
});
test('should return user by ID', async () => {
const response = await api.get('/api/users/123');
expect(response.status).toBe(200);
expect(response.data).toHaveProperty('id', '123');
expect(response.data).toHaveProperty('name');
expect(response.data).toHaveProperty('email');
});
test('should return 404 for non-existent user', async () => {
try {
await api.get('/api/users/999999');
} catch (error) {
expect(error.response.status).toBe(404);
}
});
});
describe('POST /api/users', () => {
test('should create new user', async () => {
const newUser = {
name: 'Test User',
email: 'test@example.com'
};
const response = await api.post('/api/users', newUser);
expect(response.status).toBe(201);
expect(response.data).toHaveProperty('id');
expect(response.data.name).toBe(newUser.name);
expect(response.data.email).toBe(newUser.email);
});
test('should validate required fields', async () => {
const invalidUser = { name: 'Test' }; // missing email
try {
await api.post('/api/users', invalidUser);
} catch (error) {
expect(error.response.status).toBe(400);
expect(error.response.data).toHaveProperty('error');
}
});
test('should prevent duplicate emails', async () => {
const user = {
name: 'Duplicate',
email: 'existing@example.com'
};
try {
await api.post('/api/users', user);
} catch (error) {
expect(error.response.status).toBe(409);
}
});
});
describe('Authentication', () => {
test('should reject requests without token', async () => {
const noAuthAPI = axios.create({ baseURL: API_URL });
try {
await noAuthAPI.get('/api/users');
} catch (error) {
expect(error.response.status).toBe(401);
}
});
test('should reject invalid token', async () => {
const badAuthAPI = axios.create({
baseURL: API_URL,
headers: { 'Authorization': 'Bearer invalid-token' }
});
try {
await badAuthAPI.get('/api/users');
} catch (error) {
expect(error.response.status).toBe(401);
}
});
});
});
import pytest
import requests
API_URL = 'https://api.example.com'
TOKEN = 'YOUR_TEST_TOKEN'
@pytest.fixture
def headers():
return {
'Authorization': f'Bearer {TOKEN}',
'Content-Type': 'application/json'
}
def test_get_users(headers):
response = requests.get(f'{API_URL}/api/users', headers=headers)
assert response.status_code == 200
assert isinstance(response.json(), list)
assert len(response.json()) > 0
def test_get_user_by_id(headers):
response = requests.get(f'{API_URL}/api/users/123', headers=headers)
assert response.status_code == 200
data = response.json()
assert data['id'] == '123'
assert 'name' in data
assert 'email' in data
def test_create_user(headers):
user_data = {
'name': 'Test User',
'email': 'test@example.com'
}
response = requests.post(
f'{API_URL}/api/users',
json=user_data,
headers=headers
)
assert response.status_code == 201
data = response.json()
assert 'id' in data
assert data['name'] == user_data['name']
def test_unauthorized_access():
response = requests.get(f'{API_URL}/api/users')
assert response.status_code == 401
{
"info": {
"name": "API Test Collection",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{access_token}}",
"type": "string"
}
]
},
"item": [
{
"name": "Users",
"item": [
{
"name": "Get All Users",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/users?page=1&limit=10",
"host": ["{{base_url}}"],
"path": ["api", "users"],
"query": [
{ "key": "page", "value": "1" },
{ "key": "limit", "value": "10" }
]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status code is 200', function () {",
" pm.response.to.have.status(200);",
"});",
"",
"pm.test('Response is array', function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.be.an('array');",
"});"
]
}
}
]
},
{
"name": "Create User",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"{{$randomFullName}}\",\n \"email\": \"{{$randomEmail}}\",\n \"role\": \"user\"\n}"
},
"url": {
"raw": "{{base_url}}/api/users",
"host": ["{{base_url}}"],
"path": ["api", "users"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status code is 201', function () {",
" pm.response.to.have.status(201);",
"});",
"",
"pm.test('User has ID', function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.have.property('id');",
" pm.environment.set('user_id', jsonData.id);",
"});"
]
}
}
]
}
]
}
],
"variable": [
{
"key": "base_url",
"value": "https://api.example.com"
}
]
}
# 1000 requests, 10 concurrent
ab -n 1000 -c 10 -H "Authorization: Bearer TOKEN" \
https://api.example.com/api/users
# POST request with JSON
ab -n 1000 -c 10 -p data.json -T application/json \
-H "Authorization: Bearer TOKEN" \
https://api.example.com/api/users
# artillery.yml
config:
target: 'https://api.example.com'
phases:
- duration: 60
arrivalRate: 10
name: Warm up
- duration: 300
arrivalRate: 50
name: Sustained load
defaults:
headers:
Authorization: 'Bearer YOUR_TOKEN'
scenarios:
- name: "Get users"
flow:
- get:
url: "/api/users"
expect:
- statusCode: 200
- think: 1
- post:
url: "/api/users"
json:
name: "Test User"
email: "test@example.com"
expect:
- statusCode: 201
# Run load test
artillery run artillery.yml
# Generate HTML report
artillery run artillery.yml --output report.json
artillery report report.json --output report.html
const Ajv = require('ajv');
const ajv = new Ajv();
// Define schema
const userSchema = {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
email: { type: 'string', format: 'email' },
role: { type: 'string', enum: ['user', 'admin'] },
createdAt: { type: 'string', format: 'date-time' }
},
required: ['id', 'name', 'email', 'role']
};
const validate = ajv.compile(userSchema);
// Validate response
async function testUserAPI() {
const response = await fetch('https://api.example.com/api/users/123');
const data = await response.json();
const valid = validate(data);
if (!valid) {
console.error('Validation errors:', validate.errors);
} else {
console.log('Response is valid!');
}
}
Content-Type headers200 OK - Request successful
201 Created - Resource created
204 No Content - Success, no response body
400 Bad Request - Invalid request
401 Unauthorized - Missing/invalid authentication
403 Forbidden - Not allowed to access
404 Not Found - Resource doesn't exist
409 Conflict - Resource already exists
422 Unprocessable Entity - Validation failed
429 Too Many Requests - Rate limit exceeded
500 Internal Server Error - Server error
502 Bad Gateway - Upstream server error
503 Service Unavailable - Server overloaded
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.