Skip to content
Back to skills

Api Contract First

ASecurity

Hard gate before implementing any API endpoint or service interface. Requires a written, reviewed contract (OpenAPI 3.x, protobuf, or GraphQL schema) before any implementation code is written. Prevents breaking changes, misaligned clients, and undocumented behaviour.

  • 24 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added October 16, 2026
ai-agentstypescriptapisecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 16, 2026

npx -y skills add RBraga01/a-team --skill api-contract-first --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api Contract First?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Api Contract First
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/rbraga01-api-contract-first/badge)](https://www.skillsdirectory.com/skills/rbraga01-api-contract-first)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: api-contract-first
description: Hard gate before implementing any API endpoint or service interface. Requires a written, reviewed contract (OpenAPI 3.x, protobuf, or GraphQL schema) before any implementation code is written. Prevents breaking changes, misaligned clients, and undocumented behaviour.
---

# API Contract First

## The Law

```
NO API IMPLEMENTATION WITHOUT A REVIEWED CONTRACT.
Writing endpoints before the contract is building to a spec that doesn't exist.
The contract IS the spec. Code that matches it is correct. Code that doesn't is wrong.
```

## When to Use

Use this skill before writing ANY of these:
- A new REST endpoint
- A new gRPC/protobuf service method
- A new GraphQL query, mutation, or subscription
- A new event schema (Kafka, SQS, webhooks)
- A new inter-service interface

## The Contract Process

### Step 1: Write the Contract

Choose the format that matches the project's stack:

**REST → OpenAPI 3.x**
```yaml
# docs/api/openapi.yaml
paths:
  /orders:
    post:
      summary: Create a new order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Order created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  schemas:
    CreateOrderRequest:
      type: object
      required: [userId, items]
      properties:
        userId:
          type: string
          format: uuid
        items:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/OrderItem'
```

**Events / Async → AsyncAPI or JSON Schema**
```yaml
# docs/events/order-created.yaml
name: order.created
version: 1.0.0
payload:
  type: object
  required: [orderId, userId, createdAt]
  properties:
    orderId: { type: string, format: uuid }
    userId: { type: string, format: uuid }
    createdAt: { type: string, format: date-time }
```

### Step 2: Contract Review Checklist

Before implementation begins, verify the contract satisfies all of these:

**Naming & Consistency**
- [ ] Resource names are nouns, plural (`/orders` not `/createOrder`)
- [ ] Consistent casing throughout (snake_case for JSON fields, kebab-case for URL segments)
- [ ] New names consistent with existing API vocabulary (don't introduce synonyms for existing concepts)

**Completeness**
- [ ] All error responses documented (at minimum: 400, 401, 403, 404, 422, 500)
- [ ] All required vs optional fields explicitly marked
- [ ] Field types, formats, and constraints defined (min/max, pattern, enum values)
- [ ] Pagination documented if the endpoint returns a collection

**Versioning**
- [ ] Breaking changes introduce a new version (`/v2/`) — never modify `/v1/` in a breaking way
- [ ] A change is breaking if it: removes a field, changes a field type, makes an optional field required, changes status code semantics

**Security**
- [ ] Authentication requirement stated (which scheme: Bearer, API Key, session)
- [ ] Authorisation scope documented (who can call this: any user, admin only, service-to-service)
- [ ] Rate limits noted if applicable

**Consumer Perspective**
- [ ] The contract was designed for how clients need to use it — not how it's easiest to implement
- [ ] A new team member could implement a client from this contract alone

### Step 3: Get Contract Approved

Save the contract file to `docs/api/` or `docs/events/`. The contract is reviewed before implementation begins — not after.

**Approval gate:** the `planner` agent must reference the approved contract file in the implementation plan. If no contract file is referenced, the plan is not complete.

### Step 4: Implement Against the Contract

Implementation is correct when it matches the contract exactly. The contract is the source of truth — not the implementation.

If the implementation reveals that the contract needs to change:
1. Update the contract first
2. Re-review the changed section
3. Then update the implementation

Never silently diverge from the contract. Every divergence is a breaking change waiting to happen.

### Step 5: Contract Tests

Write at least one contract test per endpoint that validates the actual response against the OpenAPI schema:

```typescript
// [VALID] — tests the real implementation against the contract
import { validate } from 'openapi-validator'
import { spec } from '../docs/api/openapi.yaml'

test('POST /orders response matches contract', async () => {
  const response = await request(app).post('/orders').send(validPayload)
  const errors = validate(spec, '/orders', 'post', response)
  expect(errors).toHaveLength(0)
})
```

## Rationalization Red Flags

These mean you are about to skip the contract step:
- "The endpoint is simple, I'll document it after"
- "The client team knows what they're getting"
- "We'll sort out the contract in the PR description"
- "It's an internal API, nobody will break"

All of these precede the same outcome: a client built on undocumented assumptions, followed by a breaking change that neither team sees coming.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.