Skip to content
Back to skills

Api Design

ASecurity

Design the HTTP contract of an ASP.NET Core API before implementing it - resource naming, methods and status codes, pagination, filtering, ProblemDetails errors, versioning, rate limiting, and idempotency. Use when adding or changing endpoints, reviewing an API's shape, or deciding conventions for a new API. For implementing endpoints, OpenAPI metadata, and .http files, use the dotnet-webapi skill.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
ai-agentsgoapi

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned November 7, 2026

npx -y skills add dmamulashvili/dotnet-agent-kit --skill api-design --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api Design?

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

Security grade badge for Api Design
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/dmamulashvili-api-design/badge)](https://www.skillsdirectory.com/skills/dmamulashvili-api-design)

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-design
description: Design the HTTP contract of an ASP.NET Core API before implementing it - resource naming, methods and status codes, pagination, filtering, ProblemDetails errors, versioning, rate limiting, and idempotency. Use when adding or changing endpoints, reviewing an API's shape, or deciding conventions for a new API. For implementing endpoints, OpenAPI metadata, and .http files, use the dotnet-webapi skill.
---

# API Design (ASP.NET Core)

Decide the contract first, write it down in the plan or PR, then implement it with the `dotnet-webapi` skill. Follow the conventions already in the codebase when they exist; use these defaults when they don't.

## Resources and URLs

- Plural nouns for collections, ids for items: `/orders`, `/orders/{id}`.
- Nest only for true ownership, at most one level: `/orders/{id}/items`.
- Lowercase, kebab-case path segments; camelCase JSON properties (the System.Text.Json web default).
- Actions that don't map to CRUD become sub-resources with POST: `POST /orders/{id}/cancel`.
- Route constraints on ids: `/orders/{id:guid}` or `{id:int}`.

## Methods and status codes

| Operation | Method | Success | Common failures |
|---|---|---|---|
| List | GET | 200 | 400 invalid query |
| Get one | GET | 200 | 404 |
| Create | POST | 201 + `Location` header + body | 400, 409 conflict, 422 business rule |
| Replace | PUT | 200 with body, or 204 | 400, 404, 409 |
| Partial update | PATCH | 200 with body | 400, 404, 409 |
| Delete | DELETE | 204 | 404 (or 204 if already gone, pick one and be consistent) |

- 401 when unauthenticated, 403 when authenticated but not allowed. Return 404 instead of 403 when revealing that the resource exists is itself a leak.
- Use typed results (`TypedResults.Ok`, `TypedResults.Created`, `TypedResults.NotFound`) so status codes appear in OpenAPI.

## Request and response models

- Separate request and response DTOs from EF entities; never bind or return entities directly.
- Requests contain only client-settable fields: no ids, timestamps, or computed values.
- Use `DateTimeOffset` in UTC with ISO 8601 for timestamps; decimals for money, never `double`.
- Enums as strings (`JsonStringEnumConverter`) so adding values doesn't break clients reading numbers.

## Errors

- Use `ProblemDetails` (RFC 9457) for every error: `builder.Services.AddProblemDetails()`, `TypedResults.Problem(...)`, and `TypedResults.ValidationProblem(errors)` for 400s with field errors.
- Keep `title` stable per error type; put specifics in `detail`. Add machine-readable codes as an extension (`"code": "order.cart_empty"`).
- Never return exception messages or stack traces outside Development.

## Pagination, filtering, sorting

- Every list endpoint is paginated with a maximum page size; never return an unbounded collection.
- Offset paging (`?page=2&pageSize=20`) for small, stable admin lists. Cursor paging (`?cursor=...&limit=20`) for large or frequently changing data and infinite scroll.
- Response envelope for lists: `{ "items": [...], "nextCursor": "..." }` or `{ "items": [...], "page": 2, "pageSize": 20, "totalCount": 135 }`. Only compute `totalCount` when the UI needs it; it costs a second query.
- Filters as query parameters named after response fields (`?status=paid&customerId=...`); sorting as `?sort=createdAt` / `?sort=-createdAt`, with an allowlist of sortable fields.

## Versioning

- Don't version until there is a breaking change you can't avoid. Additive changes (new optional fields, new endpoints) are not breaking.
- When needed, use `Asp.Versioning.Http` (minimal APIs) or `Asp.Versioning.Mvc` (controllers) with URL segment versioning (`/v1/orders`), and keep the previous version until clients have moved.
- Breaking: removing or renaming fields, changing types or meaning, new required request fields, changing status codes clients depend on.

## Rate limiting

- Use the built-in middleware: `builder.Services.AddRateLimiter(...)`, `app.UseRateLimiter()`, and `.RequireRateLimiting("policy")` per endpoint group.
- Set `RejectionStatusCode = StatusCodes.Status429TooManyRequests`; the default is 503.
- Partition by user id when authenticated, by client IP otherwise. Stricter policies on auth and expensive endpoints.

## Idempotency and concurrency

- GET, PUT, and DELETE must be idempotent. For POSTs that create money-moving or otherwise non-repeatable effects, accept an `Idempotency-Key` header and return the stored result on retries.
- Prevent lost updates with optimistic concurrency: an EF Core concurrency token surfaced as an `ETag`, checked via `If-Match`, returning 412 on mismatch (or 409 if not using ETags).

## Checklist before implementing

- [ ] URLs, methods, and status codes for every endpoint
- [ ] Request/response DTOs, with validation rules
- [ ] Error cases and their ProblemDetails shape
- [ ] Pagination and filters for every list
- [ ] Auth requirement per endpoint
- [ ] Breaking-change check against existing clients

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.