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.
npx skills add secondsky/claude-skills --skill api-testing -a claude-codeWhat 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-code2Manually: put the files in place
~/.claude/skills/api-testing/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/api-testing/
1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill api-testing -a codex2Manually: put the files in place
.agents/skills/api-testing/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill api-testing -a cursor2Manually: put the files in place
.cursor/skills/api-testing/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install secondsky/claude-skills api-testing2Manually: put the files in place
.github/skills/api-testing/SKILL.md1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill api-testing -a gemini-cli2Platform CLI
gemini skills install https://github.com/secondsky/claude-skills --path plugins/api-testing/skills/api-testingManually: put the files in place
.devin/skills/api-testing/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill api-testing -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
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.