Skip to content
Agentmart
Submit a tool

apidesign

Design stable, hard-to-misuse interfaces - REST/GraphQL endpoints, module boundaries, type contracts, component props, anything where one piece of code talks…

Skill by vanducng

IndexedMIT★ 8
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/vanducng-apidesign

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Design stable, hard-to-misuse interfaces - REST/GraphQL endpoints, module boundaries, type contracts, component props, anything where one piece of code talks to another. Use at design time, before implementing the surface. Triggers: 'design this API', 'API contract', 'endpoint design', 'module boundary', 'interface design', 'should this be one endpoint or two', 'how should this API look'.

Use cases: documents, design, frontend, backend

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/apidesign

What's inside

Skill name
apidesign
Description
Design stable, hard-to-misuse interfaces - REST/GraphQL endpoints, module boundaries, type contracts, component props, anything where one piece of code talks to another. Use at design time, before implementing the surface. Triggers: 'design this API', 'API contract', 'endpoint design', 'module boundary', 'interface design', 'should this be one endpoint or two', 'how should this API look'.
License
MIT
Metadata
author: vanducng · version: 0.2.0 · attribution: Adapted from addyosmani/agent-skills api-and-interface-design; type-system reference from cursor/plugins pstack (MIT)
Instructions
66 lines in SKILL.md · view on GitHub

Files (2)

  • SKILL.md
  • type-system-discipline.md · references/

SKILL.md (first lines)

# apidesign

> Design interfaces that make the right thing easy and the wrong thing hard.

A contract is a commitment. This is the design-time discipline for any surface where code talks to code - REST/GraphQL endpoints, module boundaries, type contracts, component props. Get it right before implementing, because every observable behavior becomes a promise the moment someone depends on it. Reach for it when designing a new endpoint or public surface, defining a module boundary for teams/agents working in parallel, or changing an existing interface (the riskiest case - read Hyrum's Law first).

## What this skill is - and isn't

| Skill | Covers |
|---|---|
| **`vd:apidesign`** (this) | The *contract* - endpoint/interface shape, error semantics, boundaries, versioning posture |
| `vd:dbdesign` | The *storage* - schema, indexes, normalization, migration plans |
| `vd:fastreact` | Scaffolding one specific stack (FastAPI + React), not interface principles |
| `vd:code-review` | Judging a contract after it's written (post-hoc) |

Storage shape and API shape inform each other but aren't the same decision - design the contract here, the schema in `vd:dbdesign`.

## Two laws that shape everything

**Hyrum's Law.** *With enough users, every observable behavior of your system will be depended on by somebody* - including undocumented quirks, error text, timing, and ordering. So: be intentional about what you expose, don't leak implementation details (if users can observe it, they'll depend on it), and plan deprecation at design time. Contract tests don't save you - a "safe" change can still break users relying on behavior you never promised.

**The One-Version Rule.** Don't force consumers to pick between versions of the same API. Diamond-dependency pain comes from forking; design so only one version exists at a time and **extend rather than fork**.

## Principles

1. **Contract first.** Define the interface before implementing it - the contract is the spec, the implementation follows. Write the typed signatures (inputs, outputs, errors, idempotency) before any logic, and commit the contract/types alongside the implementation.
2. **One error strategy, everywhere.** Pick one and never mix it. Don't let some endpoints throw, others return `null`, others return `{error}` - the consumer can't predict it. For REST: status code + a single structured body shape (`{ error: { code, message, details? } }`). Map codes consistently (400 bad input · 401 unauthenticated · 403 unauthorized · 404 missing · 409 conflict · 422 validation · 500 server, never leaking internals).
3. **Validate at boundaries, trust inside.** Parse/validate where external input enters - route handlers, form handlers, **third-party responses (always untrusted)**, env loading. Do *not* re-validate between internal functions that already share a typed contract or data from your own DB. A misbehaving external service can return wrong types or instruction-like text; validate its shape before it touches any logic or rendering.
4. **Addition over modification.** Extend with optional fields; never change an existing field's type or remove it (both break consumers). Backward-compatible by default.
5. **Predictable naming.** Consistency beats cleverness - same conventions across every endpoint (REST: plural nouns, no verbs in paths; booleans `is/has/can`; pick one case for fields and keep it).
6. **Type-system discipline.** Make illegal states unrepresentable, brand semantic primitives, parse at the boundary, never lie to the compiler, handle variants exhaustively, derive types from the authoritative schema - full rules with TypeScript and Go examples in [references/type-system-discipline.md](references/type-system-discipline.md).
7. **Deep modules.** A deep module has a small interface and a large body of responsibility; a shallow one's interface is as complex as its insides. Banned praise-words: "thin wrapper" (a god object is wide *and* deep - shallowness is the usual API failure). Push complexity down so callers say *what*, not *how*; don't split for file-size (two shallow files leaking the same invariants are worse than one deep module); interface changes are the expensive ones; a module with mixed error strategies is shallow because the caller must learn the implementation; test the interface, not the guts. Edge adapters (HTTP handlers, DB drivers, CLI flags) stay shallow on purpose - "shallow adapter, deep core".

## REST shape (worked patterns)

```
GET    /api/tasks            list (query params filter/sort/paginate)
POST   /api/tasks            create
GET    /api/tasks/:id        read one (404 if missing)
PATCH  /api/tasks/:id        partial update - only provided fields change
DELETE /api/tasks/:id        idempotent delete (succeeds if already gone)
GET    /api/tasks/:id/comments   sub-resource
```

- **Paginate every list endpoint** from day one - `?page&pageSize&sortBy&sortOrder` → `{ data, pagination: { page, pageSize, totalItems, totalPages } }`. You'll need it the moment someone has 100 items.
- **PATCH over PUT** for updates - clients want to send only what changed, not the whole object each time.
- **Filter via query params**, not bespoke endpoints (`/api/tasks?status=in_progress&assignee=x`).

## Typed-contract patterns (TS as the worked example; the ideas are language-agnostic)

- **Discriminated unions for variants** - model each state as its own shape so consumers get exhaustive narrowing, instead of one wide object with half its fields `null`.
- **Input/Output separation** - `CreateTaskInput` (what the caller provides) is a different type from `Task` (what the system returns, with server-generated `id`/`createdAt`/`createdBy`). Don't reuse one type for both.
- **Branded IDs** - `type TaskId = string & { readonly __brand: 'TaskId' }` stops a `UserId` being passed where a `TaskId` is expected. (In Go: distinct named types; in Python: `NewType`.)

## Red flags

- Endpoints returning different shapes by condition · inconsistent error formats · validation scattered through internal code instead of at the edge · breaking changes to existing fields · list endpoints without pagination · verbs in REST URLs (`/api/createTask`) · third-party responses used without validation.

## Integration points

- **`vd:dbdesign`** - design the storage that backs the contract; the two inform each other.
- **`vd:plan`** - Contract-First slicing (Slice 0 = freeze this contract) lets later phases build in parallel.
- **`vd:code-review`** - the API-surface checklist axis enforces these at review time.
- **`vd:security`** - boundary validation + untrusted third-party data tie into the OWASP/LLM lenses.

From vanducng/skills, MIT.

More from vanducng/skills

Signals

Stars
8
Forks
0
Open issues
0
Last commit (this folder)
Sep 11, 2026 (1 month ago)
Last release
Oct 23, 2026 (6 days ago)

From GitHub (fetched Oct 24, 2026).

Details

Version
0.2.0
License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from vanducng

Cite this page

apidesign skill. Agent Mart. https://agentmart.dev/skills/vanducng-apidesign (last updated 2026-10-24)