skills/curiouslearner/api-tester/SKILL.md
Quick API endpoint testing with comprehensive request/response validation.
npx skillsauth add aiskillstore/marketplace api-testerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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": "[email protected]",
"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: '[email protected]',
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': '[email protected]',
'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": "[email protected]",
"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": "[email protected]",
"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: '[email protected]'
};
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: '[email protected]'
};
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': '[email protected]'
}
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: "[email protected]"
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
development
Apple Human Interface Guidelines for content display components. Use this skill when the user asks about charts component, collection view, image view, web view, color well, image well, activity view, lockup, data visualization, content display, displaying images, rendering web content, color pickers, or presenting collections of items in Apple apps. Also use when the user says how should I display charts, what's the best way to show images, should I use a web view, how do I build a grid of items, what component shows media, or how do I present a share sheet. Cross-references: hig-foundations for color/typography/accessibility, hig-patterns for data visualization patterns, hig-components-layout for structural containers, hig-platforms for platform-specific component behavior.
tools
Automate HelpDesk tasks via Rube MCP (Composio): list tickets, manage views, use canned responses, and configure custom fields. Always search tools first for current schemas.
testing
Expert Haskell engineer specializing in advanced type systems, pure functional design, and high-reliability software. Use PROACTIVELY for type-level programming, concurrency, and architecture guidance.
tools
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.