ASPECML - API Specification with SPECML#
What is ASPECML?#
ASPECML extends SPECML for describing REST APIs. Define your endpoints, request structures, responses, and error cases in one place using familiar SPECML syntax.Single source of truth for:Authentication requirements
From ASPECML specs, generate:API documentation (OpenAPI/Swagger)
Client libraries (JavaScript, Python, etc.)
Why ASPECML?#
API docs in Swagger/OpenAPI
Request validators in code
Response types in TypeScript
When the API changes, you update all of these separately. They drift. Bugs happen.Define your API once in ASPECML. Generate everything else.CreateUserEndpoint {
method POST
path /api/users
body {
email string<isEmail>
password string<minLength:8>
username string<minLength:3>
}
response {
success {
status 201
body {
id string<ulid>
email string
username string
createdAt string<isISO>
}
}
validation_error {
status 422
body {
error string
details[] {
field string
message string
}
}
}
}
}
ASPECML vs SPECML#
ASPECML uses SPECML syntax but interprets certain fields with API-specific meaning:| Field | SPECML Interpretation | ASPECML Interpretation |
|---|
method | Field named "method" | HTTP method (GET, POST, etc.) |
path | Field named "path" | API route |
body | Nested object | Request/response body |
headers | Nested object | HTTP headers |
query | Nested object | Query parameters |
params | Nested object | Path parameters |
response | Nested object | API response scenarios |
status | Field named "status" | HTTP status code |
Everything else follows standard SPECML syntax - references, copy operators, arrays, modifiers, enums, etc.
Basic Endpoint Structure#
Every ASPECML endpoint follows this pattern:EndpointName {
method [HTTP_METHOD]
path [URL_PATH]
headers { } // Optional
query { } // Optional
params { } // Optional
body { } // Optional
response {
scenario_name {
status [CODE]
headers { } // Optional
body { } // Optional
}
}
}
response - At least one response scenario
headers - Request headers
query - Query string parameters
HTTP Methods#
Specify the HTTP method for your endpoint:GetUserEndpoint {
method GET
path /api/users/:id
}
CreateUserEndpoint {
method POST
path /api/users
}
UpdateUserEndpoint {
method PUT
path /api/users/:id
}
PatchUserEndpoint {
method PATCH
path /api/users/:id
}
DeleteUserEndpoint {
method DELETE
path /api/users/:id
}
Supported methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
URL Paths#
// Simple paths
ListUsersEndpoint {
method GET
path /api/users
}
// With path parameters (use :paramName)
GetUserEndpoint {
method GET
path /api/users/:id
}
// Nested resources
GetOrderItemEndpoint {
method GET
path /api/orders/:orderId/items/:itemId
}
// Versioned APIs
CreateUserV2Endpoint {
method POST
path /api/v2/users
}
Path parameter syntax: Use :paramName for dynamic segments.
Path Parameters#
Define and validate path parameters:GetUserEndpoint {
method GET
path /api/users/:userId
params {
userId string<ulid>
}
}
GetOrderItemEndpoint {
method GET
path /api/orders/:orderId/items/:itemId
params {
orderId string<ulid>
itemId string<ulid>
}
}
All path parameters should be defined in the params block with their validation rules.
Query Parameters#
Define URL query string parameters:ListUsersEndpoint {
method GET
path /api/users
query {
page? number<min:1>
limit? number<min:1|max:100>
status? string(active|inactive|suspended)
search? string
sortBy? string(name|email|createdAt)
sortOrder? string(asc|desc)
}
}
Usage: /api/users?page=2&limit=50&status=active&sortBy=name&sortOrder=descOptional by default: Most query parameters are optional. Use required validation if needed.
Define required or optional request headers:GetUserEndpoint {
method GET
path /api/users/:id
headers {
Authorization string
X-Request-ID? string<ulid>
Accept? string(application/json|application/xml)
}
params {
id string<ulid>
}
}
Authorization - Auth tokens
Content-Type - Request body format
Accept - Response format preference
X-Request-ID - Request tracing
X-API-Key - API authentication
Request Body#
Define the structure of request payloads:CreateUserEndpoint {
method POST
path /api/users
headers {
Content-Type string(application/json)
}
body {
email string<isEmail|lowercase>
password string<minLength:8|maxLength:100>
username string<minLength:3|maxLength:20>
firstName string<trim>
lastName string<trim>
age? number<min:13|max:120>
}
}
CreateOrderEndpoint {
method POST
path /api/orders
body {
customerId string<ulid>
items[] {
productId string<ulid>
quantity number<min:1>
unitPrice number<min:0>
}
shippingAddress {
street string
city string
zipCode string
country string<length:2|uppercase>
}
notes? string
}
}
Response Structure#
Responses contain one or more scenarios (success, error cases):CreateUserEndpoint {
method POST
path /api/users
body {
email string<isEmail>
password string<minLength:8>
}
response {
success {
status 201
body {
id string<ulid>
email string
createdAt string<isISO>
}
}
validation_error {
status 422
body {
error string
message string
}
}
server_error {
status 500
body {
error string
message string
}
}
}
}
Response scenario names are arbitrary - use descriptive names like success, not_found, unauthorized, etc.
Response Status Codes#
Define HTTP status codes for each scenario:GetUserEndpoint {
method GET
path /api/users/:id
response {
success {
status 200
body {
id string
email string
name string
}
}
not_found {
status 404
body {
error string
message string
}
}
unauthorized {
status 401
body {
error string
message string
}
}
}
}
200 - OK (successful GET, PUT, PATCH)
201 - Created (successful POST)
204 - No Content (successful DELETE)
422 - Unprocessable Entity (validation error)
500 - Internal Server Error
CreateUserEndpoint {
method POST
path /api/users
response {
success {
status 201
headers {
Location string
X-Request-ID string
X-RateLimit-Remaining number
}
body {
id string
email string
}
}
}
}
Multiple Success Scenarios#
APIs can have multiple successful outcomes:UpdateUserEndpoint {
method PUT
path /api/users/:id
body {
email? string<isEmail>
name? string
}
response {
success_updated {
status 200
body {
id string
email string
name string
updatedAt string<isISO>
}
}
success_no_changes {
status 304
body {
message string
}
}
not_found {
status 404
body {
error string
}
}
}
}
Complete Basic Example#
// Create a new user account
CreateUserEndpoint {
method POST
path /api/users
headers {
Content-Type string(application/json)
X-Request-ID? string<ulid>
}
body {
email string<isEmail|lowercase|trim>
password string<minLength:8|maxLength:100>
username string<minLength:3|maxLength:20|trim>
firstName string<trim>
lastName string<trim>
}
response {
success {
status 201
headers {
Location string
}
body {
id string<ulid>
email string
username string
firstName string
lastName string
createdAt string<isISO>
}
}
validation_error {
status 422
body {
error string
message string
details[] {
field string
message string
}
}
}
conflict {
status 409
body {
error string
message string
conflictingField string
}
}
}
}
// Retrieve user by ID
GetUserEndpoint {
method GET
path /api/users/:userId
headers {
Authorization string
}
params {
userId string<ulid>
}
response {
success {
status 200
body {
id string
email string
username string
firstName string
lastName string
createdAt string<isISO>
updatedAt string<isISO>
}
}
not_found {
status 404
body {
error string
message string
}
}
unauthorized {
status 401
body {
error string
message string
}
}
}
}
// List users with filtering
ListUsersEndpoint {
method GET
path /api/users
headers {
Authorization string
}
query {
page? number<min:1>
limit? number<min:1|max:100>
status? string(active|inactive|suspended)
search? string
}
response {
success {
status 200
body {
users[] {
id string
email string
username string
status string
}
pagination {
page number
limit number
total number
hasMore boolean
}
}
}
unauthorized {
status 401
body {
error string
message string
}
}
}
}
Key Takeaways#
1.
ASPECML uses SPECML syntax - Everything you learned applies here
2.
Specific fields have API meaning - method, path, headers, query, params, body, response, status
3.
Multiple response scenarios - Define success and all error cases
4.
Path parameters use :name - Dynamic URL segments
5.
Query parameters are typically optional - Use ? marker
6.
Request and response bodies - Use full SPECML features (references, arrays, modifiers, enums)
7.
Status codes are numbers - 200, 201, 404, 422, 500, etc.
Next sections will cover:Reusing definitions (references and copy operator)
Authentication and authorization
Real-world fintech API examples
Modified at 2025-10-08 08:20:53