# REST API Design with AI: Prompts and OpenAPI Spec Generation

> Designing REST APIs with AI: naming conventions, versioning, error handling, and OpenAPI spec generation. Ready-to-use prompts for every stage.
> Author: Roman Belov · Published: 2026-05-19 · Source: https://futurecraft.pro/blog/rest-api-design-ai/

A bad API is one of the main reasons frontend timelines blow up. Not bugs, not performance. Inconsistent endpoint names, unpredictable error responses, no documentation. A single flawed contract between backend and frontend burns dozens of hours on both sides.

AI changes how API design works. It doesn't replace the architect — it handles the tedious parts: generating OpenAPI specs, validating naming conventions, modeling error responses. With the right prompts, an LLM produces a spec that a frontend developer can read without a single follow-up question.

Below is the full cycle: from design principles to a finished AI-generated OpenAPI spec. Every step includes a prompt and a concrete result.

## REST API Design Principles That Save Time

Before opening a chat with AI, lock down the rules. LLMs only produce good specs when given clear constraints. Without them, you get inconsistent naming and mismatched responses — the exact problems you were trying to solve.

**Resources, not actions.** URLs describe nouns, HTTP methods describe actions. `/users` + `GET` instead of `/getUsers`. `/orders/{id}` + `DELETE` instead of `/deleteOrder`. It sounds obvious, but without an explicit rule AI often drifts into RPC-style endpoints: `/createUser`, `/updateOrder`.

**Plural nouns for collections.** `/users`, `/products`, `/orders`. Singular is only acceptable for singleton resources like `/users/{id}/profile`.

**Two levels of nesting, max.** `/users/{userId}/orders` is fine. `/users/{userId}/orders/{orderId}/items/{itemId}/reviews` is not. Deep nesting makes client code harder to write and breaks caching. Break it out instead: `/order-items/{itemId}/reviews`.

**Consistent response format.** Every endpoint returns data in the same wrapper. Frontend developers shouldn't have to guess whether they'll get `{ data: [...] }` or a bare array. Pick one shape for success and one for errors — then never deviate.

**Idempotency of PUT and DELETE.** Calling `PUT /users/123` repeatedly with the same data returns the same result. Repeated `DELETE /users/123` returns 204 or 404, but produces no side effects. This is critical for frontend retry logic and [circuit breaker patterns](/blog/circuit-breaker-deno-edge-functions/).

## Naming Conventions: How AI Helps Maintain Consistency

Naming conventions determine whether your API is still readable six months from now. On a project with 50+ endpoints, you can't maintain consistency manually. One developer writes `userId`, another `user_id`, a third `UserID`. The choice between a single API behind a monolith and many APIs across services is a separate concern — see the [monolith vs. microservices comparison](/blog/monolith-vs-microservices/) before deciding scope.

AI handles validation. Prompt for checking naming conventions:

```
Analyze the following list of REST API endpoints.
Check for compliance with these rules:
- URLs: kebab-case for compound words (/order-items, not /orderItems)
- Query parameters: camelCase (pageSize, sortBy)
- Request/Response body: camelCase for JSON fields
- Path parameters: camelCase ({userId}, not {user_id})
- Collections: plural nouns
- Nesting: no deeper than 2 levels

For each violation, specify: endpoint, rule, current form, corrected form.

Endpoints:
[paste list here]
```

Result: a table with specific corrections.

For generating new endpoints from a domain model:

```
Given the domain model:
- User (id, email, name, role)
- Project (id, title, ownerId, status)
- Task (id, projectId, assigneeId, title, status, priority)

Generate a list of REST endpoints for CRUD operations.
Rules:
- Base path: /api/v1
- Only necessary nested resources (1 level)
- For each endpoint: method, path, brief description, response codes

Format: Markdown table.
```

AI generates the full endpoint list in seconds. What's left is reviewing the business logic: does `PATCH /tasks/{id}/status` warrant a dedicated endpoint, or does `PATCH /tasks/{id}` cover it?

## Versioning Strategies for REST APIs

Three approaches to versioning. Each with trade-offs.

**URL-based: `/api/v1/users`**. The most common approach. Easy to implement, easy for frontend. Downside: bumping versions means updating every URL. For a public API, old versions may need to stay alive for years.

**Header-based: `Accept: application/vnd.api.v2+json`**. The URL stays clean; the version lives in a header. Downside: harder to test (you can't just open it in a browser), harder to document.

**Query parameter: `/api/users?version=2`**. The URL is stable and the version is explicit. Downside: it pollutes query parameters and conflicts with URL-based caching.

Prompt for choosing a strategy based on project context:

```
Context:
- Internal API for a mobile app and web client
- 3 consumer teams
- Release cycle: every 2 weeks
- Public API planned in 6 months

Compare three REST API versioning strategies (URL path, header, query param).
For each: pros, cons, example.
Give a recommendation with reasoning for the described context.
```

For most projects, URL-based versioning is the right call. AI isn't much help picking a strategy — the answer's almost always the same — but it's useful for planning version migrations and generating deprecation headers.

## Error Handling: A Unified Error Format via AI

Error responses shape the developer experience more than successful ones. When something breaks, the developer opens DevTools. If all they see is `500 Internal Server Error` with no details, debugging turns into guesswork.

The RFC 9457 error format (Problem Details for HTTP APIs) solves this:

```json
{
  "type": "https://api.example.com/errors/validation",
  "title": "Validation Error",
  "status": 422,
  "detail": "Request body contains invalid fields",
  "instance": "/api/v1/users",
  "errors": [
    {
      "field": "email",
      "message": "Must be a valid email address",
      "code": "INVALID_FORMAT"
    },
    {
      "field": "name",
      "message": "Must be between 2 and 100 characters",
      "code": "INVALID_LENGTH"
    }
  ]
}
```

Prompt for generating a complete error catalog:

```
Generate an error catalog for a project management REST API.
Domain: Users, Projects, Tasks.

Requirements:
- Format: RFC 9457 (Problem Details)
- Categories: validation, authentication, authorization, not_found, conflict, rate_limit, internal
- For each error: type (URI), title, status code, example detail, error code (UPPER_SNAKE_CASE)
- Error codes must be unique and machine-readable

Output format: table with columns: Category, Error Code, Status, Title, Example Detail.
```

AI generates a catalog of 20–30 errors that covers the typical scenarios. Once it exists, it's the contract. Frontend uses `error.code` for programmatic handling (`INVALID_FORMAT` triggers a field hint), `error.detail` for debugging.

Common status codes and when to use them:

| Status | When | Example |
|--------|------|---------|
| 400 | Invalid JSON, missing required fields | Request body fails to parse |
| 401 | Missing or invalid token | Expired JWT |
| 403 | Token is valid but lacks permissions | User is not the project owner |
| 404 | Resource not found | No project with that ID |
| 409 | State conflict | Email already registered |
| 422 | Business rule validation failure | Can't delete a project with active tasks |
| 429 | Rate limit exceeded | Too many requests |

A common mix-up: 400 vs 422. 400 means the request is syntactically broken — malformed JSON. 422 means the request is well-formed but semantically wrong — an email that doesn't pass validation. Frontend handles these differently, so the distinction matters.

## Generating an OpenAPI Spec with AI

An OpenAPI (Swagger) spec turns an API description into an executable contract. Frontend generates types and a client. Backend validates requests against it. QA derives test cases from it.

Writing OpenAPI YAML by hand for 30+ endpoints takes hours. AI cuts that to minutes. The key is a well-structured prompt.

### Step 1: Base Specification

```
Generate an OpenAPI 3.1 spec in YAML for a task management REST API.

Resources:
- Users: CRUD, fields (id, email, name, role, createdAt, updatedAt)
- Projects: CRUD + list by user, fields (id, title, description, status, ownerId, createdAt)
- Tasks: CRUD + list by project + update status, fields (id, title, description, status, priority, projectId, assigneeId, createdAt, updatedAt)

Requirements:
- Base path: /api/v1
- Authentication: Bearer JWT
- Pagination: cursor-based (query params: limit, cursor)
- Error format: RFC 9457
- Naming: kebab-case in URLs, camelCase in JSON body
- Reusable schemas in components/schemas
- Examples for every endpoint (requestBody + responses)
- Tags for grouping by resource
```

### Step 2: Iterative Improvement

The first pass always needs work. Give AI specific problems and it handles iteration well:

```
Improve the generated OpenAPI spec:

1. Add rate limiting headers to every response (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset)
2. Add ETag and If-None-Match for GET endpoints
3. Add Link header for pagination (RFC 8288)
4. Ensure all 4xx/5xx responses use the shared ProblemDetails schema
5. Add a discriminator for the status field in Task (open, in_progress, done, cancelled)
```

### Step 3: Validation

```
Review the OpenAPI spec for:
- Consistency of naming conventions
- Completeness of error documentation (all endpoints must describe 400, 401, 403, 500)
- Presence of examples for all requestBody and response objects
- Correct use of $ref (no duplicated schemas)
- Correctness of HTTP methods (GET has no body, DELETE returns 204)

Output a list of issues with line numbers and suggested fixes.
```

Three steps, 15–20 minutes total. A spec that would normally take hours.

## Pagination, Filtering, and Sorting: A Contract for Frontend

Pagination affects how easy it is for the frontend to work with lists. Two approaches, each with a tradeoff.

**Offset-based** (`?page=2&pageSize=20`) is easy to implement. Frontend can show page numbers. The problem: when new records are added, pages shift. A user on page 3 might see something they already saw on page 2.

**Cursor-based** (`?cursor=eyJpZCI6MTIzfQ&limit=20`) is stable. The cursor points to a record, not a position. No duplicates when new data arrives. Downside: "page 5 of 12" is gone. Best suited for infinite scroll.

Prompt for generating filter query parameters:

```
For the Tasks resource with these fields:
- status: enum (open, in_progress, done, cancelled)
- priority: enum (low, medium, high, critical)
- assigneeId: UUID
- projectId: UUID
- createdAt: datetime
- updatedAt: datetime

Generate a set of query parameters for filtering and sorting.
Rules:
- Filters: exact match and ranges (for dates)
- Multiple values as comma-separated: ?status=open,in_progress
- Sorting: ?sort=createdAt:desc,priority:asc
- Pagination: cursor-based
- Parameter format: camelCase

Output a table: Parameter, Type, Description, Example.
```

The result is a finished contract. Frontend knows exactly what to send. Backend knows exactly what to parse.

## Prompt for Full API Contract Generation

This prompt combines all the principles from above. Use it at project kickoff to produce the first version of the API contract, then iterate.

```
Role: Senior API Architect.

Task: design a REST API for [domain description].

Input:
- Domain model: [list of entities with fields and relationships]
- Consumers: [web client, mobile app, external integrations]
- Non-functional requirements: [RPS, latency, authorization]

Output format: OpenAPI 3.1 YAML.

Architectural decisions:
- Versioning: URL-based (/api/v1/)
- Auth: Bearer JWT + refresh tokens
- Pagination: cursor-based
- Error format: RFC 9457 (Problem Details)
- Naming: kebab-case URLs, camelCase JSON
- Idempotency: Idempotency-Key header for POST

For every endpoint, include:
1. Summary and description
2. All query/path/header parameters with descriptions
3. RequestBody schema with example
4. Response schemas for 2xx and all possible 4xx/5xx
5. Security requirements
6. Tags for grouping

Additional sections:
- components/schemas for all models (with required fields)
- components/securitySchemes
- components/parameters for reusable parameters (pagination, sorting)
- components/responses for standard errors

Style: production-ready, suitable for codegen (openapi-generator).
```

Think of it as a technical brief for the AI. Tighter constraints mean fewer iterations. More on how to structure context for LLMs in the [context engineering guide](/blog/context-engineering-guide/).

## API Design Validation: Checklist Before Handing Off to Frontend

Review the spec before handing it off to frontend. AI helps here too, but the final call is yours.

Prompt for a design review:

```
Review the REST API spec as a Senior Frontend Developer.
Evaluate against these criteria:

1. Predictability: consistent patterns for identical operations?
2. Self-documentation: are endpoint and field names understandable without descriptions?
3. Integration ease: can a typed client be generated?
4. Error handling: is there enough information to show to the user?
5. Pagination: is it practical to implement infinite scroll and table pagination?
6. Filtering: does it cover the main UI scenarios?
7. Caching: are ETag and Cache-Control present?

For each criterion: rating (OK / Needs improvement), specific note, example fix.
```

Manual checklist:

- All endpoints follow the same naming style
- HTTP methods match their semantics (GET does not change state)
- Every POST returns the created resource with `201 Created` and a `Location` header
- PUT and PATCH are distinct: PUT replaces the full resource, PATCH updates specific fields
- DELETE returns 204 (no body) or 200 (with the deleted resource)
- All lists support pagination
- Filter query parameters are documented with allowed values
- Error responses include machine-readable codes (not just text)
- Security scheme is applied to all endpoints (except public ones)
- No circular references in schemas

## Automation: From Specification to Code

An AI-generated OpenAPI spec is where automation starts.

**Frontend type generation.** `openapi-typescript` reads the YAML and produces TypeScript types. Frontend developers get autocomplete for every response field.

```bash
npx openapi-typescript ./openapi.yaml -o ./src/api/types.ts
```

**API client generation.** `openapi-fetch` or `orval` generate a typed client with compile-time request validation.

**Backend validation.** Middleware checks incoming requests and outgoing responses against the schema. Contract violations get caught before they reach production.

**Mock server.** `prism` from Stoplight spins up a mock API straight from the OpenAPI file. Frontend can start integration before backend is done.

```bash
npx @stoplight/prism-cli mock openapi.yaml
```

One spec, four artifacts: types, a client, request validation, and a mock server. Frontend and backend can work in parallel without waiting on each other.

## Takeaways: API Design as Engineering Discipline

REST API design with an AI assistant follows a clear sequence:

1. Lock down principles and naming conventions before generating anything
2. Generate a base OpenAPI spec via a structured prompt
3. Iterate: error handling, pagination, headers
4. Review from a frontend developer's perspective — or ask AI to take that role
5. Automate: types, client, mock server from a single spec

AI doesn't replace knowing API design. It removes the tedious work: writing YAML, checking naming, filling in examples. The architectural calls — cursor vs. offset, URL vs. header versioning, error format — still belong to the engineer, and should be documented as [Architecture Decision Records](/blog/adr-template-ai/) so the rationale survives team changes.

A spec built this way becomes the single source of truth. The same pattern of structured AI prompting works for [generating a database schema from a PRD](/blog/prd-to-db-schema/) — different artifact, same discipline of locking down constraints before generation. Frontend knows the exact response format. Backend knows what to validate. QA knows what to test. One file instead of a thread of Slack messages asking "what does this endpoint actually return."

---

*Need help with API design and development? I help startups build AI products and automate processes — [belov.works](https://belov.works).*
