Skip to main content
skill CX Codex

api-testing · secondsky — Claude Code skill: HTTP API tests

A skill that gets your agent writing HTTP API tests: Supertest for TypeScript, httpx and pytest for Python. Covers REST, GraphQL and error handling.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add secondsky/claude-skills --skill api-testing -a claude-code
Open on GitHub

What api-testing does

The skill hands the agent ready-made test patterns for two stacks. In TypeScript that means Supertest with vitest: requests through request(app), assertions on status codes, response bodies and headers. In Python it is httpx and pytest-asyncio, plus FastAPI's TestClient. Separate sections cover GraphQL queries with variables, file uploads via tmp_path, and response-time checks.

Every HTTP method gets an example: GET, POST with a body, PUT, DELETE. There is a chunk on auth — log in during beforeAll, keep the token, then hit a protected endpoint with an Authorization header. Error cases are covered too: 400 for invalid fields, 404 for a missing id.

The skill runs nothing on its own. It tells the agent what code to write, so the test framework has to be in your project already — Supertest is a separate install, and the Python path needs httpx and pytest-asyncio. If you have neither vitest nor pytest set up, expect to adapt the examples to whatever runner you do use.

What it helps with

  • write a POST test that creates a user
  • check that a protected endpoint returns 401 without a token
  • test a GraphQL query with variables
  • verify the shape of a validation error message
  • upload a file in a test and assert it was accepted

Example prompts for the agent

  • write Supertest tests for the /api/users endpoints
  • add a pytest test for login and a protected endpoint call
  • test the GraphQL user query with an id variable

How to install api-testing

1Skills CLI (Vercel)

npx skills add secondsky/claude-skills --skill api-testing -a claude-code

2Manually: put the files in place

~/.claude/skills/api-testing/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/api-testing/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about api-testing

How do I install api-testing in Claude?

Run npx skills add secondsky/claude-skills --skill api-testing -a claude-code. The skill lands at ~/.claude/skills/api-testing/SKILL.md.

What does api-testing do?

It gives the agent test patterns for HTTP APIs: Supertest in TypeScript, httpx and pytest in Python. REST, GraphQL, auth and error handling are all covered.

Do I need extra dependencies?

Yes. The TypeScript examples need Supertest, the Python ones need httpx and pytest-asyncio. The skill only suggests code, so your test runner has to come from your project.

Source text

SKILL.md · MIT
---
name: api-testing
description: HTTP API testing for TypeScript (Supertest) and Python (httpx, pytest). Test REST APIs, GraphQL, request/response validation, authentication, and error handling.
allowed-tools: Bash, Read, Edit, Write, Grep, Glob, TodoWrite
license: MIT
---

# API Testing

Expert knowledge for testing HTTP APIs with Supertest (TypeScript/JavaScript) and httpx/pytest (Python).

## TypeScript/JavaScript (Supertest)

### Installation

```bash
# Using Bun
bun add -d supertest @types/supertest

# or: npm install -D supertest @types/supertest
```

### Basic Setup

```typescript
import { describe, it, expect } from 'vitest'
import request from 'supertest'
import { app } from './app'

describe('API Tests', () => {
  it('returns health status', async () => {
    const response = await request(app)
      .get('/api/health')
      .expect(200)

    expect(response.body).toEqual({ status: 'ok' })
  })

  it('creates a user', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({ name: 'John Doe', email: '[email protected]' })
      .expect(201)

    expect(response.body).toMatchObject({
      id: expect.any(Number),
      name: 'John Doe',
    })
  })

  it('validates required fields', async () => {
    await request(app)
      .post('/api/users')
      .send({ name: 'John Doe' })
      .expect(400)
  })
})
```

### Request Methods

```typescript
// GET
await request(app).get('/api/users').expect(200)

// POST with body
await request(app)
  .post('/api/users')
  .send({ name: 'John' })
  .expect(201)

// PUT
await request(app)
  .put('/api/users/1')
  .send({ name: 'Jane' })
  .expect(200)

// DELETE
await request(app).delete('/api/users/1').expect(204)
```

### Headers and Query Parameters

```typescript
// Set headers
await request(app)
  .get('/api/protected')
  .set('Authorization', 'Bearer token123')
  .expect(200)

// Query parameters
await request(app)
  .get('/api/users')
  .query({ page: 1, limit: 10 })
  .expect(200)
```

### Authentication Testing

```typescript
describe('Authentication', () => {
  let authToken: string

  beforeAll(async () => {
    const response = await request(app)
      .post('/api/auth/login')
      .send({ email: '[email protected]', password: 'password123' })
      .expect(200)

    authToken = response.body.token
  })

  it('accesses protected endpoint', async () => {
    await request(app)
      .get('/api/protected')
      .set('Authorization', `Bearer ${authToken}`)
      .expect(200)
  })

  it('rejects without token', async () => {
    await request(app).get('/api/protected').expect(401)
  })
})
```

### Error Handling

```typescript
it('handles validation errors', async () => {
  const response = await request(app)
    .post('/api/users')
    .send({ email: 'invalid-email' })
    .expect(400)

  expect(response.body).toMatchObject({
    error: 'Validation failed',
    details: expect.any(Array),
  })
})

it('handles not found', async () => {
  await request(app).get('/api/users/999999').expect(404)
})
```

## Python (httpx + pytest)

### Installation

```bash
uv add --dev httpx pytest-asyncio
```

### Basic Setup

```python
import pytest
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_health_check():
    response = client.get("/api/health")
    assert response.status_code == 200
    assert response.json() == {"status": "ok"}

def test_create_user():
    response = client.post(
        "/api/users",
        json={"name": "John Doe", "email": "[email protected]"}
    )
    assert response.status_code == 201
    data = response.json()
    assert data["name"] == "John Doe"
    assert "id" in data

def test_not_found():
    response = client.get("/api/users/999")
    assert response.status_code == 404
```

### Fixtures

```python
@pytest.fixture
def auth_token(client):
    response = client.post(
        "/api/auth/login",
        json={"email": "[email protected]", "password": "password123"}
    )
    return response.json()["token"]

def test_protected_endpoint(client, auth_token):
    response = client.get(
        "/api/protected",
        headers={"Authorization": f"Bearer {auth_token}"}
    )
    assert response.status_code == 200
```

### File Upload

```python
def test_file_upload(client, tmp_path):
    test_file = tmp_path / "test.txt"
    test_file.write_text("test content")

    with open(test_file, "rb") as f:
        response = client.post(
            "/api/upload",
            files={"file": ("test.txt", f, "text/plain")}
        )

    assert response.status_code == 200
```

## GraphQL Testing

```typescript
it('queries GraphQL endpoint', async () => {
  const query = `
    query GetUser($id: ID!) {
      user(id: $id) { id name email }
    }
  `

  const response = await request(app)
    .post('/graphql')
    .send({ query, variables: { id: '1' } })
    .expect(200)

  expect(response.body.data.user).toMatchObject({
    id: '1',
    name: expect.any(String),
  })
})
```

## Performance Testing

```typescript
it('responds within acceptable time', async () => {
  const start = Date.now()
  await request(app).get('/api/users').expect(200)
  const duration = Date.now() - start
  expect(duration).toBeLessThan(100) // 100ms threshold
})
```

## Best Practices

- Group related endpoints in `describe` blocks
- Reset database between tests
- Validate status codes first
- Check response structure
- Test error message format
- Mock external services
- Test both happy path and error cases

## See Also

- `vitest-testing` - Unit testing framework
- `playwright-testing` - E2E API testing
- `test-quality-analysis` - Test quality patterns

© secondsky · MIT · secondsky/claude-skills

Similar skills

Everything for Testing and QA →

api-testing by other authors comes first.

From the same set89

aceternity-ui This skill gives your agent the Aceternity UI playbook: 100+ animated React components for Next.js with Tailwind. Useful for hero sections, parallax and 3D effects. CX Codex +1 1,500installs vitest-testing A skill that teaches your agent to write unit and integration tests with Vitest in TypeScript and JavaScript projects. Handy when you need config, mocks and coverage set up fast. CX Codex +1 1,200installs motion A skill that feeds your agent the Motion (Framer Motion) docs for React: drag-and-drop, scroll effects, layout transitions. Useful when the agent guesses at props. CX Codex +1 1,100installs playwright A Playwright skill for browser automation and end-to-end testing. It finds your running dev server and writes the test script for the task. CX Codex +1 1,000installs rest-api-design This skill hands your agent a set of REST conventions: resource names, HTTP methods, status codes and JSON response shape. Useful when you start a new API or want existing endpoints to match. CX Codex +1 586installs web-performance-optimization A skill that walks your agent through code splitting, lazy loading, caching and Core Web Vitals monitoring for web apps. CX Codex +1 557installs api-authentication A skill that helps your coding agent write API authentication: JWT, OAuth 2.0, API keys, sessions and security headers. CX Codex +1 533installs web-performance-audit A skill that audits page speed: pulls Core Web Vitals, finds bottlenecks and points at what to fix. Useful when LCP or CLS drifts out of range. CX Codex +1 526installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor