Back to Skills

api-tester

CuriousLearner
Updated Today
18 views
16
3
16
View on GitHub
Testingtestingapidesign

About

The api-tester skill enables developers to quickly validate API endpoints with comprehensive request/response testing. It handles functional validation, performance benchmarking, and security checks while generating test cases and scripts. Use it for verifying API contracts, testing edge cases, and automating endpoint validation during development.

Documentation

API Tester Skill

Quick API endpoint testing with comprehensive request/response validation.

Instructions

You are an API testing expert. When invoked:

  1. Test API Endpoints:

    • Validate HTTP methods (GET, POST, PUT, PATCH, DELETE)
    • Test request headers and body formats
    • Verify response status codes
    • Validate response schema and data types
    • Check authentication and authorization
  2. Generate Test Cases:

    • Create curl commands for testing
    • Generate Postman collections
    • Write automated test scripts
    • Test edge cases and error scenarios
    • Validate API contracts
  3. Performance Testing:

    • Load testing with concurrent requests
    • Response time benchmarking
    • Rate limit verification
    • Timeout handling
    • Connection pooling tests
  4. Security Testing:

    • Authentication/authorization checks
    • Input validation testing
    • SQL injection prevention
    • XSS prevention
    • CORS configuration

Usage Examples

@api-tester
@api-tester --endpoint /api/users
@api-tester --method POST
@api-tester --load-test
@api-tester --generate-collection

REST API Testing

GET Request Examples

Basic GET Request

# 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

JavaScript/Node.js

// 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;
  }
}

Python

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)

POST Request Examples

Create Resource

# 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

JavaScript/Node.js

// 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;
  }
}

Python

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/PATCH Request Examples

# 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 Request Examples

# 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"

Authentication Examples

Bearer Token (JWT)

# 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..."

API Key

# 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"

Basic Auth

# 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="

OAuth 2.0

// 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();
}

GraphQL Testing

Basic Query

# 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" }
  }'

GraphQL Mutations

// 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;
}

Automated Testing

Jest Test Suite

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);
      }
    });
  });
});

Python pytest

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

Postman Collection

Collection Structure

{
  "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"
    }
  ]
}

Load Testing

Using Apache Bench

# 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

Using Artillery

# 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

Response Validation

Schema Validation

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!');
  }
}

Best Practices

Request Best Practices

  • Always set appropriate Content-Type headers
  • Use proper HTTP methods (GET for reads, POST for creates, etc.)
  • Include authentication tokens securely
  • Handle timeouts and retries
  • Validate input before sending
  • Use HTTPS for production APIs

Response Handling

  • Check status codes before parsing
  • Handle errors gracefully
  • Validate response schema
  • Log requests and responses for debugging
  • Implement exponential backoff for retries

Security Testing

  • Test with invalid tokens
  • Test without authentication
  • Attempt SQL injection in parameters
  • Test XSS in input fields
  • Verify CORS settings
  • Test rate limiting

Error Scenarios to Test

  • Invalid authentication
  • Missing required fields
  • Invalid data types
  • Duplicate resources
  • Not found (404)
  • Server errors (500)
  • Rate limit exceeded (429)
  • Network timeouts

Common HTTP Status Codes

200 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

Notes

  • Always test in development/staging before production
  • Use environment variables for API URLs and tokens
  • Document all test cases and expected results
  • Automate testing in CI/CD pipeline
  • Monitor API performance and error rates
  • Keep Postman collections updated
  • Test edge cases and error scenarios
  • Validate both success and failure paths
  • Use proper authentication methods
  • Never commit API keys or tokens to version control

Quick Install

/plugin add https://github.com/CuriousLearner/devkit/tree/main/api-tester

Copy and paste this command in Claude Code to install this skill

GitHub 仓库

CuriousLearner/devkit
Path: skills/api-tester

Related Skills

evaluating-llms-harness

Testing

This Claude Skill runs the lm-evaluation-harness to benchmark LLMs across 60+ standardized academic tasks like MMLU and GSM8K. It's designed for developers to compare model quality, track training progress, or report academic results. The tool supports various backends including HuggingFace and vLLM models.

View skill

langchain

Meta

LangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.

View skill

Algorithmic Art Generation

Meta

This skill helps developers create algorithmic art using p5.js, focusing on generative art, computational aesthetics, and interactive visualizations. It automatically activates for topics like "generative art" or "p5.js visualization" and guides you through creating unique algorithms with features like seeded randomness, flow fields, and particle systems. Use it when you need to build reproducible, code-driven artistic patterns.

View skill

webapp-testing

Testing

This Claude Skill provides a Playwright-based toolkit for testing local web applications through Python scripts. It enables frontend verification, UI debugging, screenshot capture, and log viewing while managing server lifecycles. Use it for browser automation tasks but run scripts directly rather than reading their source code to avoid context pollution.

View skill