536 lines
13 KiB
Markdown
536 lines
13 KiB
Markdown
## Example for OpenAPI
|
|
|
|
|
|
```yaml
|
|
openapi: '3.0.3'
|
|
info:
|
|
title: Todo REST API
|
|
version: '1.0.0'
|
|
description: A RESTful API for managing todo items
|
|
|
|
servers:
|
|
- url: /api/v1
|
|
description: Base API path
|
|
|
|
components:
|
|
schemas:
|
|
Todo:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
readOnly: true
|
|
title:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 200
|
|
description:
|
|
type: string
|
|
maxLength: 2000
|
|
completed:
|
|
type: boolean
|
|
default: false
|
|
dueDate:
|
|
type: string
|
|
format: date-time
|
|
userId:
|
|
type: string
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
readOnly: true
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
readOnly: true
|
|
required:
|
|
- id
|
|
- title
|
|
- completed
|
|
- userId
|
|
- createdAt
|
|
- updatedAt
|
|
|
|
TodoCreate:
|
|
type: object
|
|
properties:
|
|
title:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 200
|
|
description:
|
|
type: string
|
|
maxLength: 2000
|
|
dueDate:
|
|
type: string
|
|
format: date-time
|
|
userId:
|
|
type: string
|
|
required:
|
|
- title
|
|
- userId
|
|
|
|
TodoUpdate:
|
|
type: object
|
|
properties:
|
|
title:
|
|
type: string
|
|
minLength: 1
|
|
maxLength: 200
|
|
description:
|
|
type: string
|
|
maxLength: 2000
|
|
completed:
|
|
type: boolean
|
|
dueDate:
|
|
type: string
|
|
format: date-time
|
|
minProperties: 1
|
|
|
|
TodoList:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Todo'
|
|
metadata:
|
|
type: object
|
|
properties:
|
|
total:
|
|
type: integer
|
|
minimum: 0
|
|
limit:
|
|
type: integer
|
|
minimum: 1
|
|
offset:
|
|
type: integer
|
|
minimum: 0
|
|
required:
|
|
- total
|
|
- limit
|
|
- offset
|
|
required:
|
|
- data
|
|
- metadata
|
|
|
|
TodoResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
$ref: '#/components/schemas/Todo'
|
|
required:
|
|
- data
|
|
|
|
Error:
|
|
type: object
|
|
properties:
|
|
error:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
enum:
|
|
- VALIDATION_ERROR
|
|
- UNAUTHORIZED
|
|
- FORBIDDEN
|
|
- NOT_FOUND
|
|
- RATE_LIMIT_EXCEEDED
|
|
- INTERNAL_ERROR
|
|
message:
|
|
type: string
|
|
details:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
field:
|
|
type: string
|
|
message:
|
|
type: string
|
|
required:
|
|
- field
|
|
- message
|
|
required:
|
|
- code
|
|
- message
|
|
|
|
parameters:
|
|
TodoId:
|
|
name: todoId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
UserId:
|
|
name: userId
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
Status:
|
|
name: status
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [active, completed]
|
|
Limit:
|
|
name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 50
|
|
Offset:
|
|
name: offset
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 0
|
|
default: 0
|
|
SortBy:
|
|
name: sortBy
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [createdAt, dueDate]
|
|
default: createdAt
|
|
SortOrder:
|
|
name: sortOrder
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [asc, desc]
|
|
default: desc
|
|
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
|
|
security:
|
|
- bearerAuth: []
|
|
|
|
paths:
|
|
/todos:
|
|
get:
|
|
summary: List todos
|
|
parameters:
|
|
- $ref: '#/components/parameters/UserId'
|
|
- $ref: '#/components/parameters/Status'
|
|
- $ref: '#/components/parameters/Limit'
|
|
- $ref: '#/components/parameters/Offset'
|
|
- $ref: '#/components/parameters/SortBy'
|
|
- $ref: '#/components/parameters/SortOrder'
|
|
responses:
|
|
'200':
|
|
description: Successfully retrieved todos
|
|
headers:
|
|
ETag:
|
|
schema:
|
|
type: string
|
|
Last-Modified:
|
|
schema:
|
|
type: string
|
|
X-Request-ID:
|
|
schema:
|
|
type: string
|
|
X-RateLimit-Limit:
|
|
schema:
|
|
type: integer
|
|
X-RateLimit-Remaining:
|
|
schema:
|
|
type: integer
|
|
X-RateLimit-Reset:
|
|
schema:
|
|
type: integer
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TodoList'
|
|
'400':
|
|
description: Invalid parameters
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'429':
|
|
description: Too many requests
|
|
headers:
|
|
Retry-After:
|
|
schema:
|
|
type: integer
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
post:
|
|
summary: Create a new todo
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TodoCreate'
|
|
responses:
|
|
'201':
|
|
description: Todo created successfully
|
|
headers:
|
|
Location:
|
|
schema:
|
|
type: string
|
|
format: uri
|
|
ETag:
|
|
schema:
|
|
type: string
|
|
X-Request-ID:
|
|
schema:
|
|
type: string
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TodoResponse'
|
|
'400':
|
|
description: Invalid input
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/todos/{todoId}:
|
|
parameters:
|
|
- $ref: '#/components/parameters/TodoId'
|
|
|
|
get:
|
|
summary: Get a specific todo
|
|
responses:
|
|
'200':
|
|
description: Successfully retrieved todo
|
|
headers:
|
|
ETag:
|
|
schema:
|
|
type: string
|
|
Last-Modified:
|
|
schema:
|
|
type: string
|
|
X-Request-ID:
|
|
schema:
|
|
type: string
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TodoResponse'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'404':
|
|
description: Todo not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
patch:
|
|
summary: Update a todo
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TodoUpdate'
|
|
responses:
|
|
'200':
|
|
description: Todo updated successfully
|
|
headers:
|
|
ETag:
|
|
schema:
|
|
type: string
|
|
X-Request-ID:
|
|
schema:
|
|
type: string
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TodoResponse'
|
|
'400':
|
|
description: Invalid input
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'404':
|
|
description: Todo not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
delete:
|
|
summary: Delete a todo
|
|
responses:
|
|
'204':
|
|
description: Todo deleted successfully
|
|
headers:
|
|
X-Request-ID:
|
|
schema:
|
|
type: string
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'404':
|
|
description: Todo not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
```
|
|
|
|
```wit
|
|
package api:todos@1.0.0;
|
|
|
|
// Common types used across the API
|
|
interface types {
|
|
// Authentication types derived from OpenAPI security schemes
|
|
record bearer-token {
|
|
token: string,
|
|
}
|
|
|
|
// Core resource type
|
|
record todo {
|
|
id: string,
|
|
title: string,
|
|
description: option<string>,
|
|
completed: bool,
|
|
due-date: option<string>,
|
|
user-id: string,
|
|
created-at: string,
|
|
updated-at: string,
|
|
}
|
|
|
|
variant error {
|
|
unauthorized,
|
|
not-found,
|
|
validation-error(list<string>),
|
|
rate-limited { retry-after: u32 },
|
|
server-error,
|
|
}
|
|
}
|
|
|
|
interface todos-collection {
|
|
use types.{todo, bearer-token, error};
|
|
|
|
// Request/response types with domain-appropriate fields
|
|
record list-request {
|
|
auth: bearer-token,
|
|
user-id: string,
|
|
status: option<string>,
|
|
limit: option<u32>,
|
|
%offset: option<u32>,
|
|
}
|
|
|
|
record list-response {
|
|
items: list<todo>,
|
|
total: u32,
|
|
limit: u32,
|
|
%offset: u32,
|
|
version: string, // From ETag
|
|
last-updated: option<string>, // From Last-Modified
|
|
}
|
|
|
|
record create-request {
|
|
auth: bearer-token,
|
|
title: string,
|
|
description: option<string>,
|
|
due-date: option<string>,
|
|
user-id: string,
|
|
}
|
|
|
|
// Note: Response includes versioning info directly in return type
|
|
list: func(request: list-request) -> result<list-response, error>;
|
|
|
|
create: func(request: create-request) -> result<todo, error>;
|
|
}
|
|
|
|
interface todos-resource {
|
|
use types.{todo, bearer-token, error};
|
|
|
|
record update-request {
|
|
auth: bearer-token,
|
|
title: option<string>,
|
|
description: option<string>,
|
|
completed: option<bool>,
|
|
due-date: option<string>,
|
|
expected-version: option<string>, // If-Match header
|
|
}
|
|
|
|
get: func(id: string, auth: bearer-token) -> result<todo, error>;
|
|
|
|
update: func(id: string, request: update-request) -> result<todo, error>;
|
|
|
|
delete: func(id: string, auth: bearer-token) -> result<unit, error>;
|
|
}
|
|
|
|
world todos-api {
|
|
export todos-collection;
|
|
export todos-resource;
|
|
}
|
|
``` |