Nested Saves
Create, update, and delete nested records in a single request
API Definition
config/apis/clever_rabbit.rb
rb
# frozen_string_literal: true
Apiwork::API.define '/clever_rabbit' do
key_format :camel
export :openapi
export :apiwork
resources :orders
endModels
app/models/clever_rabbit/order.rb
rb
# frozen_string_literal: true
module CleverRabbit
class Order < ApplicationRecord
has_many :line_items, dependent: :destroy
has_one :shipping_address, dependent: :destroy
accepts_nested_attributes_for :line_items, allow_destroy: true
accepts_nested_attributes_for :shipping_address, allow_destroy: true
validates :order_number, presence: true
end
endDatabase Table
| Column | Type | Nullable | Default |
|---|---|---|---|
| id | string | ||
| created_at | datetime | ||
| order_number | string | ||
| status | string | ✓ | pending |
| total | decimal | ✓ | |
| updated_at | datetime |
app/models/clever_rabbit/line_item.rb
rb
# frozen_string_literal: true
module CleverRabbit
class LineItem < ApplicationRecord
belongs_to :order
validates :product_name, presence: true
end
endDatabase Table
| Column | Type | Nullable | Default |
|---|---|---|---|
| id | string | ||
| created_at | datetime | ||
| order_id | string | ||
| product_name | string | ||
| quantity | integer | ✓ | 1 |
| unit_price | decimal | ✓ | |
| updated_at | datetime |
app/models/clever_rabbit/shipping_address.rb
rb
# frozen_string_literal: true
module CleverRabbit
class ShippingAddress < ApplicationRecord
belongs_to :order
validates :street, :city, :postal_code, :country, presence: true
end
endDatabase Table
| Column | Type | Nullable | Default |
|---|---|---|---|
| id | string | ||
| city | string | ||
| country | string | ||
| created_at | datetime | ||
| order_id | string | ||
| postal_code | string | ||
| street | string | ||
| updated_at | datetime |
Representations
app/representations/clever_rabbit/order_representation.rb
rb
# frozen_string_literal: true
module CleverRabbit
class OrderRepresentation < Apiwork::Representation::Base
attribute :id
attribute :order_number, writable: true
attribute :status
attribute :total
attribute :created_at
attribute :updated_at
has_many :line_items, include: :always, writable: true
has_one :shipping_address, include: :always, writable: true
end
endapp/representations/clever_rabbit/line_item_representation.rb
rb
# frozen_string_literal: true
module CleverRabbit
class LineItemRepresentation < Apiwork::Representation::Base
attribute :id
attribute :product_name, writable: true
attribute :quantity, writable: true
attribute :unit_price, writable: true
end
endapp/representations/clever_rabbit/shipping_address_representation.rb
rb
# frozen_string_literal: true
module CleverRabbit
class ShippingAddressRepresentation < Apiwork::Representation::Base
attribute :id
attribute :street, writable: true
attribute :city, writable: true
attribute :postal_code, writable: true
attribute :country, writable: true
end
endContracts
app/contracts/clever_rabbit/order_contract.rb
rb
# frozen_string_literal: true
module CleverRabbit
class OrderContract < Apiwork::Contract::Base
representation OrderRepresentation
end
endControllers
app/controllers/clever_rabbit/orders_controller.rb
rb
# frozen_string_literal: true
module CleverRabbit
class OrdersController < ApplicationController
before_action :set_order, only: %i[show update destroy]
def index
orders = Order.all
expose orders
end
def show
expose order
end
def create
order = Order.create(contract.body[:order])
expose order
end
def update
order.update(contract.body[:order])
expose order
end
def destroy
order.destroy
expose order
end
private
attr_reader :order
def set_order
@order = Order.find(params[:id])
end
end
endRequest Examples
List all orders
Request
http
GET /clever_rabbit/ordersResponse 200
json
{
"orders": [
{
"id": "38948b8f-2c00-5384-8f16-b1105fcd31fb",
"orderNumber": "ORD-001",
"status": "pending",
"total": null,
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z",
"lineItems": [],
"shippingAddress": null
},
{
"id": "4c65a30e-5d9c-5523-b6bd-25e85ed94165",
"orderNumber": "ORD-002",
"status": "pending",
"total": null,
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z",
"lineItems": [],
"shippingAddress": null
}
],
"pagination": {
"items": 2,
"total": 1,
"current": 1,
"next": null,
"prev": null
}
}Get order details
Request
http
GET /clever_rabbit/orders/38948b8f-2c00-5384-8f16-b1105fcd31fbResponse 200
json
{
"order": {
"id": "38948b8f-2c00-5384-8f16-b1105fcd31fb",
"orderNumber": "ORD-001",
"status": "pending",
"total": null,
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z",
"lineItems": [],
"shippingAddress": null
}
}Create order with nested records
Request
http
POST /clever_rabbit/orders
Content-Type: application/json
{
"order": {
"orderNumber": "ORD-001",
"lineItems": [
{
"OP": "create",
"productName": "Widget",
"quantity": 2,
"unitPrice": 29.99
},
{
"OP": "create",
"productName": "Gadget",
"quantity": 1,
"unitPrice": 49.99
}
],
"shippingAddress": {
"OP": "create",
"street": "123 Main St",
"city": "Springfield",
"postalCode": "12345",
"country": "USA"
}
}
}Response 201
json
{
"order": {
"id": "38948b8f-2c00-5384-8f16-b1105fcd31fb",
"orderNumber": "ORD-001",
"status": "pending",
"total": null,
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z",
"lineItems": [
{
"id": "ad73acbb-0926-5060-9b75-5888bde61fc7",
"productName": "Widget",
"quantity": 2,
"unitPrice": "29.99"
},
{
"id": "987c1624-9b7b-5467-910c-4dc0035b91ee",
"productName": "Gadget",
"quantity": 1,
"unitPrice": "49.99"
}
],
"shippingAddress": {
"id": "3cb3bbd4-ed44-5c37-a3bf-f77ea95a7e5a",
"street": "123 Main St",
"city": "Springfield",
"postalCode": "12345",
"country": "USA"
}
}
}Update order with new items
Request
http
PATCH /clever_rabbit/orders/38948b8f-2c00-5384-8f16-b1105fcd31fb
Content-Type: application/json
{
"order": {
"lineItems": [
{
"OP": "create",
"productName": "New Item",
"quantity": 3,
"unitPrice": 19.99
}
]
}
}Response 200
json
{
"order": {
"id": "38948b8f-2c00-5384-8f16-b1105fcd31fb",
"orderNumber": "ORD-001",
"status": "pending",
"total": null,
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z",
"lineItems": [
{
"id": "ad73acbb-0926-5060-9b75-5888bde61fc7",
"productName": "New Item",
"quantity": 3,
"unitPrice": "19.99"
}
],
"shippingAddress": null
}
}Delete an order
Request
http
DELETE /clever_rabbit/orders/38948b8f-2c00-5384-8f16-b1105fcd31fbResponse 204
Remove nested record
Request
http
PATCH /clever_rabbit/orders/38948b8f-2c00-5384-8f16-b1105fcd31fb
Content-Type: application/json
{
"order": {
"lineItems": [
{
"OP": "delete",
"id": "987c1624-9b7b-5467-910c-4dc0035b91ee"
}
]
}
}Response 200
json
{
"order": {
"id": "38948b8f-2c00-5384-8f16-b1105fcd31fb",
"orderNumber": "ORD-001",
"status": "pending",
"total": null,
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z",
"lineItems": [
{
"id": "ad73acbb-0926-5060-9b75-5888bde61fc7",
"productName": "Widget to Keep",
"quantity": 2,
"unitPrice": "19.99"
}
],
"shippingAddress": null
}
}Exports
OpenAPI
yml
---
openapi: 3.1.0
info:
title: "/clever_rabbit"
version: 1.0.0
paths:
"/orders":
get:
operationId: ordersIndex
parameters:
- in: query
name: page
required: false
schema:
"$ref": "#/components/schemas/orderPage"
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
orders:
items:
"$ref": "#/components/schemas/order"
type: array
pagination:
"$ref": "#/components/schemas/offsetPagination"
type: object
required:
- orders
- pagination
description: ''
post:
operationId: ordersCreate
requestBody:
content:
application/json:
schema:
properties:
order:
"$ref": "#/components/schemas/orderCreatePayload"
type: object
required:
- order
required: true
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
order:
"$ref": "#/components/schemas/order"
type: object
required:
- order
description: ''
'422':
description: Unprocessable Entity
content:
application/json:
schema:
properties:
issues:
items:
"$ref": "#/components/schemas/error"
type: array
required:
- issues
type: object
"/orders/{id}":
get:
operationId: ordersShow
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
order:
"$ref": "#/components/schemas/order"
type: object
required:
- order
description: ''
patch:
operationId: ordersUpdate
parameters:
- in: path
name: id
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
properties:
order:
"$ref": "#/components/schemas/orderUpdatePayload"
type: object
required:
- order
required: true
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
order:
"$ref": "#/components/schemas/order"
type: object
required:
- order
description: ''
'422':
description: Unprocessable Entity
content:
application/json:
schema:
properties:
issues:
items:
"$ref": "#/components/schemas/error"
type: array
required:
- issues
type: object
delete:
operationId: ordersDestroy
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'204':
description: ''
components:
schemas:
error:
properties:
issues:
items:
"$ref": "#/components/schemas/errorIssue"
type: array
layer:
enum:
- http
- contract
- domain
type: string
type: object
required:
- issues
- layer
errorIssue:
properties:
code:
type: string
detail:
type: string
meta:
properties: {}
type: object
path:
items:
oneOf:
- type: string
- type: integer
type: array
pointer:
type: string
type: object
required:
- code
- detail
- meta
- path
- pointer
lineItem:
properties:
id:
type: string
productName:
type: string
quantity:
type:
- integer
- 'null'
unitPrice:
type:
- number
- 'null'
type: object
required:
- id
- productName
- quantity
- unitPrice
lineItemNestedCreatePayload:
properties:
OP:
const: create
type: string
productName:
type: string
quantity:
type:
- integer
- 'null'
minimum: -2147483648
maximum: 2147483647
default: 1
unitPrice:
type:
- number
- 'null'
minimum: -99999999.99
maximum: 99999999.99
default:
type: object
required:
- OP
- productName
lineItemNestedDeletePayload:
properties:
OP:
const: delete
type: string
id:
type: string
type: object
required:
- OP
- id
lineItemNestedPayload:
oneOf:
- "$ref": "#/components/schemas/lineItemNestedCreatePayload"
- "$ref": "#/components/schemas/lineItemNestedUpdatePayload"
- "$ref": "#/components/schemas/lineItemNestedDeletePayload"
discriminator:
mapping:
create: "#/components/schemas/lineItemNestedCreatePayload"
update: "#/components/schemas/lineItemNestedUpdatePayload"
delete: "#/components/schemas/lineItemNestedDeletePayload"
propertyName: OP
lineItemNestedUpdatePayload:
properties:
OP:
const: update
type: string
id:
type: string
productName:
type: string
quantity:
type:
- integer
- 'null'
minimum: -2147483648
maximum: 2147483647
unitPrice:
type:
- number
- 'null'
minimum: -99999999.99
maximum: 99999999.99
type: object
required:
- OP
offsetPagination:
properties:
current:
type: integer
items:
type: integer
next:
type:
- integer
- 'null'
prev:
type:
- integer
- 'null'
total:
type: integer
type: object
required:
- current
- items
- total
order:
properties:
createdAt:
type: string
format: date-time
id:
type: string
lineItems:
items:
"$ref": "#/components/schemas/lineItem"
type: array
orderNumber:
type: string
shippingAddress:
"$ref": "#/components/schemas/shippingAddress"
status:
type:
- string
- 'null'
total:
type:
- number
- 'null'
updatedAt:
type: string
format: date-time
type: object
required:
- createdAt
- id
- lineItems
- orderNumber
- shippingAddress
- status
- total
- updatedAt
orderCreatePayload:
properties:
lineItems:
items:
"$ref": "#/components/schemas/lineItemNestedPayload"
type: array
orderNumber:
type: string
shippingAddress:
"$ref": "#/components/schemas/shippingAddressNestedPayload"
type: object
required:
- orderNumber
orderPage:
properties:
number:
type: integer
minimum: 1
size:
type: integer
minimum: 1
maximum: 100
type: object
orderUpdatePayload:
properties:
lineItems:
items:
"$ref": "#/components/schemas/lineItemNestedPayload"
type: array
orderNumber:
type: string
shippingAddress:
"$ref": "#/components/schemas/shippingAddressNestedPayload"
type: object
shippingAddress:
properties:
city:
type: string
country:
type: string
id:
type: string
postalCode:
type: string
street:
type: string
type: object
required:
- city
- country
- id
- postalCode
- street
shippingAddressNestedCreatePayload:
properties:
OP:
const: create
type: string
city:
type: string
country:
type: string
postalCode:
type: string
street:
type: string
type: object
required:
- OP
- city
- country
- postalCode
- street
shippingAddressNestedDeletePayload:
properties:
OP:
const: delete
type: string
id:
type: string
type: object
required:
- OP
- id
shippingAddressNestedPayload:
oneOf:
- "$ref": "#/components/schemas/shippingAddressNestedCreatePayload"
- "$ref": "#/components/schemas/shippingAddressNestedUpdatePayload"
- "$ref": "#/components/schemas/shippingAddressNestedDeletePayload"
discriminator:
mapping:
create: "#/components/schemas/shippingAddressNestedCreatePayload"
update: "#/components/schemas/shippingAddressNestedUpdatePayload"
delete: "#/components/schemas/shippingAddressNestedDeletePayload"
propertyName: OP
shippingAddressNestedUpdatePayload:
properties:
OP:
const: update
type: string
city:
type: string
country:
type: string
id:
type: string
postalCode:
type: string
street:
type: string
type: object
required:
- OPApiwork
json
{
"base_path": "/clever_rabbit",
"enums": [
{
"deprecated": false,
"description": null,
"example": null,
"name": "error_layer",
"scope": null,
"values": [
"http",
"contract",
"domain"
]
}
],
"error_codes": [
{
"description": "Unprocessable Entity",
"name": "unprocessable_entity",
"status": 422
}
],
"fingerprint": "eb5ecce994239f15",
"info": null,
"locales": [],
"resources": [
{
"actions": [
{
"name": "orders.index",
"deprecated": false,
"description": null,
"method": "get",
"operation_id": null,
"path": "/orders",
"raises": [],
"request": {
"body": [],
"description": null,
"query": [
{
"name": "page",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "order_page"
}
]
},
"response": {
"body": {
"deprecated": null,
"description": null,
"nullable": null,
"optional": null,
"type": "object",
"partial": null,
"shape": [
{
"name": "meta",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "object",
"partial": false,
"shape": []
},
{
"name": "orders",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "array",
"example": null,
"max": null,
"min": null,
"of": {
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "order"
}
},
{
"name": "pagination",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "offset_pagination"
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
},
{
"name": "orders.show",
"deprecated": false,
"description": null,
"method": "get",
"operation_id": null,
"path": "/orders/:id",
"raises": [],
"request": {
"body": [],
"description": null,
"query": []
},
"response": {
"body": {
"deprecated": null,
"description": null,
"nullable": null,
"optional": null,
"type": "object",
"partial": null,
"shape": [
{
"name": "meta",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "object",
"partial": false,
"shape": []
},
{
"name": "order",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "order"
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
},
{
"name": "orders.create",
"deprecated": false,
"description": null,
"method": "post",
"operation_id": null,
"path": "/orders",
"raises": [
"unprocessable_entity"
],
"request": {
"body": [
{
"name": "order",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "order_create_payload"
}
],
"description": null,
"query": []
},
"response": {
"body": {
"deprecated": null,
"description": null,
"nullable": null,
"optional": null,
"type": "object",
"partial": null,
"shape": [
{
"name": "meta",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "object",
"partial": false,
"shape": []
},
{
"name": "order",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "order"
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
},
{
"name": "orders.update",
"deprecated": false,
"description": null,
"method": "patch",
"operation_id": null,
"path": "/orders/:id",
"raises": [
"unprocessable_entity"
],
"request": {
"body": [
{
"name": "order",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "order_update_payload"
}
],
"description": null,
"query": []
},
"response": {
"body": {
"deprecated": null,
"description": null,
"nullable": null,
"optional": null,
"type": "object",
"partial": null,
"shape": [
{
"name": "meta",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "object",
"partial": false,
"shape": []
},
{
"name": "order",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "order"
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
},
{
"name": "orders.destroy",
"deprecated": false,
"description": null,
"method": "delete",
"operation_id": null,
"path": "/orders/:id",
"raises": [],
"request": {
"body": [],
"description": null,
"query": []
},
"response": {
"body": null,
"description": null,
"no_content": true
},
"summary": null,
"tags": []
}
],
"identifier": "orders",
"name": "orders",
"parent_identifiers": [],
"path": "orders",
"resources": [],
"scope": "order"
}
],
"types": [
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "error_issue",
"scope": null,
"type": "object",
"extends": [],
"shape": [
{
"name": "code",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "detail",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "meta",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "object",
"partial": false,
"shape": []
},
{
"name": "path",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "array",
"example": null,
"max": null,
"min": null,
"of": {
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "union",
"discriminator": "",
"variants": [
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "integer",
"example": null,
"format": null,
"max": null,
"min": null
}
]
}
},
{
"name": "pointer",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "line_item",
"scope": "line_item",
"type": "object",
"extends": [],
"shape": [
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "productName",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "quantity",
"deprecated": false,
"description": null,
"nullable": true,
"optional": false,
"type": "integer",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "unitPrice",
"deprecated": false,
"description": null,
"nullable": true,
"optional": false,
"type": "decimal",
"example": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "line_item_nested_create_payload",
"scope": "line_item",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "create"
},
{
"name": "productName",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "quantity",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "integer",
"default": 1,
"example": null,
"format": null,
"max": 2147483647,
"min": -2147483648
},
{
"name": "unitPrice",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "decimal",
"default": null,
"example": null,
"max": 99999999.99,
"min": -99999999.99
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "line_item_nested_delete_payload",
"scope": "line_item",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "delete"
},
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "line_item_nested_update_payload",
"scope": "line_item",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "update"
},
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "productName",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "quantity",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "integer",
"example": null,
"format": null,
"max": 2147483647,
"min": -2147483648
},
{
"name": "unitPrice",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "decimal",
"example": null,
"max": 99999999.99,
"min": -99999999.99
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "offset_pagination",
"scope": null,
"type": "object",
"extends": [],
"shape": [
{
"name": "current",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "integer",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "items",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "integer",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "next",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "integer",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "prev",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "integer",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "total",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "integer",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "order_page",
"scope": "order",
"type": "object",
"extends": [],
"shape": [
{
"name": "number",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "integer",
"example": null,
"format": null,
"max": null,
"min": 1
},
{
"name": "size",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "integer",
"example": null,
"format": null,
"max": 100,
"min": 1
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "shipping_address",
"scope": "shipping_address",
"type": "object",
"extends": [],
"shape": [
{
"name": "city",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "country",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "postalCode",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "street",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "shipping_address_nested_create_payload",
"scope": "shipping_address",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "create"
},
{
"name": "city",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "country",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "postalCode",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "street",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "shipping_address_nested_delete_payload",
"scope": "shipping_address",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "delete"
},
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "shipping_address_nested_update_payload",
"scope": "shipping_address",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "update"
},
{
"name": "city",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "country",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "postalCode",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "street",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "error",
"scope": null,
"type": "object",
"extends": [],
"shape": [
{
"name": "issues",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "array",
"example": null,
"max": null,
"min": null,
"of": {
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "error_issue"
}
},
{
"name": "layer",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "error_layer"
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "line_item_nested_payload",
"scope": "line_item",
"type": "union",
"discriminator": "OP",
"variants": [
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "line_item_nested_create_payload",
"tag": "create"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "line_item_nested_update_payload",
"tag": "update"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "line_item_nested_delete_payload",
"tag": "delete"
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "order",
"scope": "order",
"type": "object",
"extends": [],
"shape": [
{
"name": "createdAt",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "datetime",
"example": null
},
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "lineItems",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "array",
"example": null,
"max": null,
"min": null,
"of": {
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "line_item"
}
},
{
"name": "orderNumber",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "shippingAddress",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "shipping_address"
},
{
"name": "status",
"deprecated": false,
"description": null,
"nullable": true,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "total",
"deprecated": false,
"description": null,
"nullable": true,
"optional": false,
"type": "decimal",
"example": null,
"max": null,
"min": null
},
{
"name": "updatedAt",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "datetime",
"example": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "shipping_address_nested_payload",
"scope": "shipping_address",
"type": "union",
"discriminator": "OP",
"variants": [
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "shipping_address_nested_create_payload",
"tag": "create"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "shipping_address_nested_update_payload",
"tag": "update"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "shipping_address_nested_delete_payload",
"tag": "delete"
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "order_create_payload",
"scope": "order",
"type": "object",
"extends": [],
"shape": [
{
"name": "lineItems",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "array",
"example": null,
"max": null,
"min": null,
"of": {
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "line_item_nested_payload"
}
},
{
"name": "orderNumber",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "shippingAddress",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "shipping_address_nested_payload"
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "order_update_payload",
"scope": "order",
"type": "object",
"extends": [],
"shape": [
{
"name": "lineItems",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "array",
"example": null,
"max": null,
"min": null,
"of": {
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "line_item_nested_payload"
}
},
{
"name": "orderNumber",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "shippingAddress",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "shipping_address_nested_payload"
}
]
}
]
}Codegen
TypeScript
ts
export type ErrorLayer = 'http' | 'contract' | 'domain';
export interface ErrorIssue {
code: string;
detail: string;
meta: Record<string, unknown>;
path: string | number[];
pointer: string;
}
export interface OffsetPagination {
current: number;
items: number;
next?: number | null;
prev?: number | null;
total: number;
}
export interface Error {
issues: ErrorIssue[];
layer: ErrorLayer;
}ts
export * from './line-item';
export * from './order';
export * from './shipping-address';ts
export interface LineItem {
id: string;
productName: string;
quantity: number | null;
unitPrice: number | null;
}
export interface LineItemNestedCreatePayload {
OP: 'create';
productName: string;
quantity?: number | null;
unitPrice?: number | null;
}
export interface LineItemNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface LineItemNestedUpdatePayload {
id?: string;
OP: 'update';
productName?: string;
quantity?: number | null;
unitPrice?: number | null;
}
export type LineItemNestedPayload =
| (LineItemNestedCreatePayload & { OP: 'create' })
| (LineItemNestedUpdatePayload & { OP: 'update' })
| (LineItemNestedDeletePayload & { OP: 'delete' });ts
import type { LineItem, LineItemNestedPayload } from './line-item';
import type {
ShippingAddress,
ShippingAddressNestedPayload,
} from './shipping-address';
export interface OrderPage {
number?: number;
size?: number;
}
export interface Order {
createdAt: string;
id: string;
lineItems: LineItem[];
orderNumber: string;
shippingAddress: ShippingAddress;
status: string | null;
total: number | null;
updatedAt: string;
}
export interface OrderCreatePayload {
lineItems?: LineItemNestedPayload[];
orderNumber: string;
shippingAddress?: ShippingAddressNestedPayload;
}
export interface OrderUpdatePayload {
lineItems?: LineItemNestedPayload[];
orderNumber?: string;
shippingAddress?: ShippingAddressNestedPayload;
}ts
export interface ShippingAddress {
city: string;
country: string;
id: string;
postalCode: string;
street: string;
}
export interface ShippingAddressNestedCreatePayload {
city: string;
country: string;
OP: 'create';
postalCode: string;
street: string;
}
export interface ShippingAddressNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface ShippingAddressNestedUpdatePayload {
city?: string;
country?: string;
id?: string;
OP: 'update';
postalCode?: string;
street?: string;
}
export type ShippingAddressNestedPayload =
| (ShippingAddressNestedCreatePayload & { OP: 'create' })
| (ShippingAddressNestedUpdatePayload & { OP: 'update' })
| (ShippingAddressNestedDeletePayload & { OP: 'delete' });ts
export * from './orders';ts
import type { OffsetPagination } from '../api';
import type {
Order,
OrderCreatePayload,
OrderPage,
OrderUpdatePayload,
} from '../domains/order';
export type OrdersIndexMethod = 'GET';
export type OrdersIndexPath = '/orders';
export interface OrdersIndexRequestQuery {
page?: OrderPage;
}
export type OrdersIndexResponseBody = {
meta?: Record<string, unknown>;
orders: Order[];
pagination: OffsetPagination;
};
export interface OrdersIndexRequest {
query: OrdersIndexRequestQuery;
}
export interface OrdersIndexResponse {
body: OrdersIndexResponseBody;
}
export interface OrdersIndex {
method: OrdersIndexMethod;
path: OrdersIndexPath;
request: OrdersIndexRequest;
response: OrdersIndexResponse;
}
export type OrdersShowMethod = 'GET';
export type OrdersShowPath = '/orders/:id';
export interface OrdersShowPathParams {
id: string;
}
export type OrdersShowResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersShowResponse {
body: OrdersShowResponseBody;
}
export interface OrdersShow {
method: OrdersShowMethod;
path: OrdersShowPath;
pathParams: OrdersShowPathParams;
response: OrdersShowResponse;
}
export type OrdersCreateMethod = 'POST';
export type OrdersCreatePath = '/orders';
export interface OrdersCreateRequestBody {
order: OrderCreatePayload;
}
export type OrdersCreateResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersCreateRequest {
body: OrdersCreateRequestBody;
}
export interface OrdersCreateResponse {
body: OrdersCreateResponseBody;
}
export type OrdersCreateErrors = 422;
export interface OrdersCreate {
errors: OrdersCreateErrors;
method: OrdersCreateMethod;
path: OrdersCreatePath;
request: OrdersCreateRequest;
response: OrdersCreateResponse;
}
export type OrdersUpdateMethod = 'PATCH';
export type OrdersUpdatePath = '/orders/:id';
export interface OrdersUpdatePathParams {
id: string;
}
export interface OrdersUpdateRequestBody {
order: OrderUpdatePayload;
}
export type OrdersUpdateResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersUpdateRequest {
body: OrdersUpdateRequestBody;
}
export interface OrdersUpdateResponse {
body: OrdersUpdateResponseBody;
}
export type OrdersUpdateErrors = 422;
export interface OrdersUpdate {
errors: OrdersUpdateErrors;
method: OrdersUpdateMethod;
path: OrdersUpdatePath;
pathParams: OrdersUpdatePathParams;
request: OrdersUpdateRequest;
response: OrdersUpdateResponse;
}
export type OrdersDestroyMethod = 'DELETE';
export type OrdersDestroyPath = '/orders/:id';
export interface OrdersDestroyPathParams {
id: string;
}
export interface OrdersDestroy {
method: OrdersDestroyMethod;
path: OrdersDestroyPath;
pathParams: OrdersDestroyPathParams;
}Zod
ts
import * as z from 'zod';
export const ErrorLayerSchema = z.enum(['contract', 'domain', 'http']);
export const ErrorIssueSchema = z.object({
code: z.string(),
detail: z.string(),
meta: z.record(z.string(), z.unknown()),
path: z.array(z.union([z.string(), z.number().int()])),
pointer: z.string(),
});
export const OffsetPaginationSchema = z.object({
current: z.number().int(),
items: z.number().int(),
next: z.number().int().nullable().optional(),
prev: z.number().int().nullable().optional(),
total: z.number().int(),
});
export const ErrorSchema = z.object({
issues: z.array(ErrorIssueSchema),
layer: ErrorLayerSchema,
});
export type ErrorLayer = 'contract' | 'domain' | 'http';
export interface ErrorIssue {
code: string;
detail: string;
meta: Record<string, unknown>;
path: string | number[];
pointer: string;
}
export interface OffsetPagination {
current: number;
items: number;
next?: number | null;
prev?: number | null;
total: number;
}
export interface Error {
issues: ErrorIssue[];
layer: ErrorLayer;
}ts
export * from './line-item';
export * from './order';
export * from './shipping-address';ts
import * as z from 'zod';
export const LineItemSchema = z.object({
id: z.string(),
productName: z.string(),
quantity: z.number().int().nullable(),
unitPrice: z.number().nullable(),
});
export const LineItemNestedCreatePayloadSchema = z.object({
OP: z.literal('create'),
productName: z.string(),
quantity: z
.number()
.int()
.min(-2147483648)
.max(2147483647)
.nullable()
.default(1),
unitPrice: z
.number()
.min(-99999999.99)
.max(99999999.99)
.nullable()
.default(null),
});
export const LineItemNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const LineItemNestedUpdatePayloadSchema = z.object({
id: z.string().optional(),
OP: z.literal('update'),
productName: z.string().optional(),
quantity: z
.number()
.int()
.min(-2147483648)
.max(2147483647)
.nullable()
.optional(),
unitPrice: z
.number()
.min(-99999999.99)
.max(99999999.99)
.nullable()
.optional(),
});
export const LineItemNestedPayloadSchema = z.discriminatedUnion('OP', [
LineItemNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
LineItemNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
LineItemNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface LineItem {
id: string;
productName: string;
quantity: number | null;
unitPrice: number | null;
}
export interface LineItemNestedCreatePayload {
OP: 'create';
productName: string;
quantity?: number | null;
unitPrice?: number | null;
}
export interface LineItemNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface LineItemNestedUpdatePayload {
id?: string;
OP: 'update';
productName?: string;
quantity?: number | null;
unitPrice?: number | null;
}
export type LineItemNestedPayload =
| (LineItemNestedCreatePayload & { OP: 'create' })
| (LineItemNestedUpdatePayload & { OP: 'update' })
| (LineItemNestedDeletePayload & { OP: 'delete' });ts
import type { LineItem, LineItemNestedPayload } from './line-item';
import type {
ShippingAddress,
ShippingAddressNestedPayload,
} from './shipping-address';
import * as z from 'zod';
import { LineItemNestedPayloadSchema, LineItemSchema } from './line-item';
import {
ShippingAddressNestedPayloadSchema,
ShippingAddressSchema,
} from './shipping-address';
export const OrderPageSchema = z.object({
number: z.number().int().min(1).optional(),
size: z.number().int().min(1).max(100).optional(),
});
export const OrderSchema = z.object({
createdAt: z.iso.datetime(),
id: z.string(),
lineItems: z.array(LineItemSchema),
orderNumber: z.string(),
shippingAddress: ShippingAddressSchema,
status: z.string().nullable(),
total: z.number().nullable(),
updatedAt: z.iso.datetime(),
});
export const OrderCreatePayloadSchema = z.object({
lineItems: z.array(LineItemNestedPayloadSchema).optional(),
orderNumber: z.string(),
shippingAddress: ShippingAddressNestedPayloadSchema.optional(),
});
export const OrderUpdatePayloadSchema = z.object({
lineItems: z.array(LineItemNestedPayloadSchema).optional(),
orderNumber: z.string().optional(),
shippingAddress: ShippingAddressNestedPayloadSchema.optional(),
});
export interface OrderPage {
number?: number;
size?: number;
}
export interface Order {
createdAt: string;
id: string;
lineItems: LineItem[];
orderNumber: string;
shippingAddress: ShippingAddress;
status: string | null;
total: number | null;
updatedAt: string;
}
export interface OrderCreatePayload {
lineItems?: LineItemNestedPayload[];
orderNumber: string;
shippingAddress?: ShippingAddressNestedPayload;
}
export interface OrderUpdatePayload {
lineItems?: LineItemNestedPayload[];
orderNumber?: string;
shippingAddress?: ShippingAddressNestedPayload;
}ts
import * as z from 'zod';
export const ShippingAddressSchema = z.object({
city: z.string(),
country: z.string(),
id: z.string(),
postalCode: z.string(),
street: z.string(),
});
export const ShippingAddressNestedCreatePayloadSchema = z.object({
city: z.string(),
country: z.string(),
OP: z.literal('create'),
postalCode: z.string(),
street: z.string(),
});
export const ShippingAddressNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const ShippingAddressNestedUpdatePayloadSchema = z.object({
city: z.string().optional(),
country: z.string().optional(),
id: z.string().optional(),
OP: z.literal('update'),
postalCode: z.string().optional(),
street: z.string().optional(),
});
export const ShippingAddressNestedPayloadSchema = z.discriminatedUnion('OP', [
ShippingAddressNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
ShippingAddressNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
ShippingAddressNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface ShippingAddress {
city: string;
country: string;
id: string;
postalCode: string;
street: string;
}
export interface ShippingAddressNestedCreatePayload {
city: string;
country: string;
OP: 'create';
postalCode: string;
street: string;
}
export interface ShippingAddressNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface ShippingAddressNestedUpdatePayload {
city?: string;
country?: string;
id?: string;
OP: 'update';
postalCode?: string;
street?: string;
}
export type ShippingAddressNestedPayload =
| (ShippingAddressNestedCreatePayload & { OP: 'create' })
| (ShippingAddressNestedUpdatePayload & { OP: 'update' })
| (ShippingAddressNestedDeletePayload & { OP: 'delete' });ts
export * from './orders';ts
import type { OffsetPagination } from '../api';
import type {
Order,
OrderCreatePayload,
OrderPage,
OrderUpdatePayload,
} from '../domains/order';
import * as z from 'zod';
import { OffsetPaginationSchema } from '../api';
import {
OrderCreatePayloadSchema,
OrderPageSchema,
OrderSchema,
OrderUpdatePayloadSchema,
} from '../domains/order';
export const OrdersIndexRequestQuerySchema = z.object({
page: OrderPageSchema.optional(),
});
export const OrdersIndexResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
orders: z.array(OrderSchema),
pagination: OffsetPaginationSchema,
});
export const OrdersShowPathParamsSchema = z.object({ id: z.string() });
export const OrdersShowResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
order: OrderSchema,
});
export const OrdersCreateRequestBodySchema = z.object({
order: OrderCreatePayloadSchema,
});
export const OrdersCreateResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
order: OrderSchema,
});
export const OrdersUpdatePathParamsSchema = z.object({ id: z.string() });
export const OrdersUpdateRequestBodySchema = z.object({
order: OrderUpdatePayloadSchema,
});
export const OrdersUpdateResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
order: OrderSchema,
});
export const OrdersDestroyPathParamsSchema = z.object({ id: z.string() });
export type OrdersIndexMethod = 'GET';
export type OrdersIndexPath = '/orders';
export interface OrdersIndexRequestQuery {
page?: OrderPage;
}
export type OrdersIndexResponseBody = {
meta?: Record<string, unknown>;
orders: Order[];
pagination: OffsetPagination;
};
export interface OrdersIndexRequest {
query: OrdersIndexRequestQuery;
}
export interface OrdersIndexResponse {
body: OrdersIndexResponseBody;
}
export interface OrdersIndex {
method: OrdersIndexMethod;
path: OrdersIndexPath;
request: OrdersIndexRequest;
response: OrdersIndexResponse;
}
export type OrdersShowMethod = 'GET';
export type OrdersShowPath = '/orders/:id';
export interface OrdersShowPathParams {
id: string;
}
export type OrdersShowResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersShowResponse {
body: OrdersShowResponseBody;
}
export interface OrdersShow {
method: OrdersShowMethod;
path: OrdersShowPath;
pathParams: OrdersShowPathParams;
response: OrdersShowResponse;
}
export type OrdersCreateMethod = 'POST';
export type OrdersCreatePath = '/orders';
export interface OrdersCreateRequestBody {
order: OrderCreatePayload;
}
export type OrdersCreateResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersCreateRequest {
body: OrdersCreateRequestBody;
}
export interface OrdersCreateResponse {
body: OrdersCreateResponseBody;
}
export type OrdersCreateErrors = 422;
export interface OrdersCreate {
errors: OrdersCreateErrors;
method: OrdersCreateMethod;
path: OrdersCreatePath;
request: OrdersCreateRequest;
response: OrdersCreateResponse;
}
export type OrdersUpdateMethod = 'PATCH';
export type OrdersUpdatePath = '/orders/:id';
export interface OrdersUpdatePathParams {
id: string;
}
export interface OrdersUpdateRequestBody {
order: OrderUpdatePayload;
}
export type OrdersUpdateResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersUpdateRequest {
body: OrdersUpdateRequestBody;
}
export interface OrdersUpdateResponse {
body: OrdersUpdateResponseBody;
}
export type OrdersUpdateErrors = 422;
export interface OrdersUpdate {
errors: OrdersUpdateErrors;
method: OrdersUpdateMethod;
path: OrdersUpdatePath;
pathParams: OrdersUpdatePathParams;
request: OrdersUpdateRequest;
response: OrdersUpdateResponse;
}
export type OrdersDestroyMethod = 'DELETE';
export type OrdersDestroyPath = '/orders/:id';
export interface OrdersDestroyPathParams {
id: string;
}
export interface OrdersDestroy {
method: OrdersDestroyMethod;
path: OrdersDestroyPath;
pathParams: OrdersDestroyPathParams;
}Sorbus
ts
import * as z from 'zod';
export const ErrorLayerSchema = z.enum(['contract', 'domain', 'http']);
export const ErrorIssueSchema = z.object({
code: z.string(),
detail: z.string(),
meta: z.record(z.string(), z.unknown()),
path: z.array(z.union([z.string(), z.number().int()])),
pointer: z.string(),
});
export const OffsetPaginationSchema = z.object({
current: z.number().int(),
items: z.number().int(),
next: z.number().int().nullable().optional(),
prev: z.number().int().nullable().optional(),
total: z.number().int(),
});
export const ErrorSchema = z.object({
issues: z.array(ErrorIssueSchema),
layer: ErrorLayerSchema,
});
export type ErrorLayer = 'contract' | 'domain' | 'http';
export interface ErrorIssue {
code: string;
detail: string;
meta: Record<string, unknown>;
path: string | number[];
pointer: string;
}
export interface OffsetPagination {
current: number;
items: number;
next?: number | null;
prev?: number | null;
total: number;
}
export interface Error {
issues: ErrorIssue[];
layer: ErrorLayer;
}ts
import type { OrdersOperationTree } from './endpoints';
import { createClientFactory } from 'sorbus';
import { contract } from './contract';
export interface Client {
orders: OrdersOperationTree;
}
export const createClient = createClientFactory<Client>(contract);ts
import { ErrorSchema } from './api';
import { orders } from './endpoints';
export const contract = {
endpoints: {
orders,
},
error: ErrorSchema,
} as const;ts
export * from './line-item';
export * from './order';
export * from './shipping-address';ts
import * as z from 'zod';
export const LineItemSchema = z.object({
id: z.string(),
productName: z.string(),
quantity: z.number().int().nullable(),
unitPrice: z.number().nullable(),
});
export const LineItemNestedCreatePayloadSchema = z.object({
OP: z.literal('create'),
productName: z.string(),
quantity: z
.number()
.int()
.min(-2147483648)
.max(2147483647)
.nullable()
.default(1),
unitPrice: z
.number()
.min(-99999999.99)
.max(99999999.99)
.nullable()
.default(null),
});
export const LineItemNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const LineItemNestedUpdatePayloadSchema = z.object({
id: z.string().optional(),
OP: z.literal('update'),
productName: z.string().optional(),
quantity: z
.number()
.int()
.min(-2147483648)
.max(2147483647)
.nullable()
.optional(),
unitPrice: z
.number()
.min(-99999999.99)
.max(99999999.99)
.nullable()
.optional(),
});
export const LineItemNestedPayloadSchema = z.discriminatedUnion('OP', [
LineItemNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
LineItemNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
LineItemNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface LineItem {
id: string;
productName: string;
quantity: number | null;
unitPrice: number | null;
}
export interface LineItemNestedCreatePayload {
OP: 'create';
productName: string;
quantity?: number | null;
unitPrice?: number | null;
}
export interface LineItemNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface LineItemNestedUpdatePayload {
id?: string;
OP: 'update';
productName?: string;
quantity?: number | null;
unitPrice?: number | null;
}
export type LineItemNestedPayload =
| (LineItemNestedCreatePayload & { OP: 'create' })
| (LineItemNestedUpdatePayload & { OP: 'update' })
| (LineItemNestedDeletePayload & { OP: 'delete' });ts
import type { LineItem, LineItemNestedPayload } from './line-item';
import type {
ShippingAddress,
ShippingAddressNestedPayload,
} from './shipping-address';
import * as z from 'zod';
import { LineItemNestedPayloadSchema, LineItemSchema } from './line-item';
import {
ShippingAddressNestedPayloadSchema,
ShippingAddressSchema,
} from './shipping-address';
export const OrderPageSchema = z.object({
number: z.number().int().min(1).optional(),
size: z.number().int().min(1).max(100).optional(),
});
export const OrderSchema = z.object({
createdAt: z.iso.datetime(),
id: z.string(),
lineItems: z.array(LineItemSchema),
orderNumber: z.string(),
shippingAddress: ShippingAddressSchema,
status: z.string().nullable(),
total: z.number().nullable(),
updatedAt: z.iso.datetime(),
});
export const OrderCreatePayloadSchema = z.object({
lineItems: z.array(LineItemNestedPayloadSchema).optional(),
orderNumber: z.string(),
shippingAddress: ShippingAddressNestedPayloadSchema.optional(),
});
export const OrderUpdatePayloadSchema = z.object({
lineItems: z.array(LineItemNestedPayloadSchema).optional(),
orderNumber: z.string().optional(),
shippingAddress: ShippingAddressNestedPayloadSchema.optional(),
});
export interface OrderPage {
number?: number;
size?: number;
}
export interface Order {
createdAt: string;
id: string;
lineItems: LineItem[];
orderNumber: string;
shippingAddress: ShippingAddress;
status: string | null;
total: number | null;
updatedAt: string;
}
export interface OrderCreatePayload {
lineItems?: LineItemNestedPayload[];
orderNumber: string;
shippingAddress?: ShippingAddressNestedPayload;
}
export interface OrderUpdatePayload {
lineItems?: LineItemNestedPayload[];
orderNumber?: string;
shippingAddress?: ShippingAddressNestedPayload;
}ts
import * as z from 'zod';
export const ShippingAddressSchema = z.object({
city: z.string(),
country: z.string(),
id: z.string(),
postalCode: z.string(),
street: z.string(),
});
export const ShippingAddressNestedCreatePayloadSchema = z.object({
city: z.string(),
country: z.string(),
OP: z.literal('create'),
postalCode: z.string(),
street: z.string(),
});
export const ShippingAddressNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const ShippingAddressNestedUpdatePayloadSchema = z.object({
city: z.string().optional(),
country: z.string().optional(),
id: z.string().optional(),
OP: z.literal('update'),
postalCode: z.string().optional(),
street: z.string().optional(),
});
export const ShippingAddressNestedPayloadSchema = z.discriminatedUnion('OP', [
ShippingAddressNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
ShippingAddressNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
ShippingAddressNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface ShippingAddress {
city: string;
country: string;
id: string;
postalCode: string;
street: string;
}
export interface ShippingAddressNestedCreatePayload {
city: string;
country: string;
OP: 'create';
postalCode: string;
street: string;
}
export interface ShippingAddressNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface ShippingAddressNestedUpdatePayload {
city?: string;
country?: string;
id?: string;
OP: 'update';
postalCode?: string;
street?: string;
}
export type ShippingAddressNestedPayload =
| (ShippingAddressNestedCreatePayload & { OP: 'create' })
| (ShippingAddressNestedUpdatePayload & { OP: 'update' })
| (ShippingAddressNestedDeletePayload & { OP: 'delete' });ts
export * from './orders';ts
import type { Operation } from 'sorbus';
import type { OffsetPagination } from '../api';
import type {
Order,
OrderCreatePayload,
OrderPage,
OrderUpdatePayload,
} from '../domains/order';
import * as z from 'zod';
import { OffsetPaginationSchema } from '../api';
import {
OrderCreatePayloadSchema,
OrderPageSchema,
OrderSchema,
OrderUpdatePayloadSchema,
} from '../domains/order';
export const OrdersIndexRequestQuerySchema = z.object({
page: OrderPageSchema.optional(),
});
export const OrdersIndexResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
orders: z.array(OrderSchema),
pagination: OffsetPaginationSchema,
});
export const OrdersShowPathParamsSchema = z.object({ id: z.string() });
export const OrdersShowResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
order: OrderSchema,
});
export const OrdersCreateRequestBodySchema = z.object({
order: OrderCreatePayloadSchema,
});
export const OrdersCreateResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
order: OrderSchema,
});
export const OrdersUpdatePathParamsSchema = z.object({ id: z.string() });
export const OrdersUpdateRequestBodySchema = z.object({
order: OrderUpdatePayloadSchema,
});
export const OrdersUpdateResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
order: OrderSchema,
});
export const OrdersDestroyPathParamsSchema = z.object({ id: z.string() });
export type OrdersIndexMethod = 'GET';
export type OrdersIndexPath = '/orders';
export interface OrdersIndexRequestQuery {
page?: OrderPage;
}
export type OrdersIndexResponseBody = {
meta?: Record<string, unknown>;
orders: Order[];
pagination: OffsetPagination;
};
export interface OrdersIndexRequest {
query: OrdersIndexRequestQuery;
}
export interface OrdersIndexResponse {
body: OrdersIndexResponseBody;
}
export interface OrdersIndex {
method: OrdersIndexMethod;
path: OrdersIndexPath;
request: OrdersIndexRequest;
response: OrdersIndexResponse;
}
export type OrdersShowMethod = 'GET';
export type OrdersShowPath = '/orders/:id';
export interface OrdersShowPathParams {
id: string;
}
export type OrdersShowResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersShowResponse {
body: OrdersShowResponseBody;
}
export interface OrdersShow {
method: OrdersShowMethod;
path: OrdersShowPath;
pathParams: OrdersShowPathParams;
response: OrdersShowResponse;
}
export type OrdersCreateMethod = 'POST';
export type OrdersCreatePath = '/orders';
export interface OrdersCreateRequestBody {
order: OrderCreatePayload;
}
export type OrdersCreateResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersCreateRequest {
body: OrdersCreateRequestBody;
}
export interface OrdersCreateResponse {
body: OrdersCreateResponseBody;
}
export type OrdersCreateErrors = 422;
export interface OrdersCreate {
errors: OrdersCreateErrors;
method: OrdersCreateMethod;
path: OrdersCreatePath;
request: OrdersCreateRequest;
response: OrdersCreateResponse;
}
export type OrdersUpdateMethod = 'PATCH';
export type OrdersUpdatePath = '/orders/:id';
export interface OrdersUpdatePathParams {
id: string;
}
export interface OrdersUpdateRequestBody {
order: OrderUpdatePayload;
}
export type OrdersUpdateResponseBody = {
meta?: Record<string, unknown>;
order: Order;
};
export interface OrdersUpdateRequest {
body: OrdersUpdateRequestBody;
}
export interface OrdersUpdateResponse {
body: OrdersUpdateResponseBody;
}
export type OrdersUpdateErrors = 422;
export interface OrdersUpdate {
errors: OrdersUpdateErrors;
method: OrdersUpdateMethod;
path: OrdersUpdatePath;
pathParams: OrdersUpdatePathParams;
request: OrdersUpdateRequest;
response: OrdersUpdateResponse;
}
export type OrdersDestroyMethod = 'DELETE';
export type OrdersDestroyPath = '/orders/:id';
export interface OrdersDestroyPathParams {
id: string;
}
export interface OrdersDestroy {
method: OrdersDestroyMethod;
path: OrdersDestroyPath;
pathParams: OrdersDestroyPathParams;
}
export const orders = {
create: {
errors: [422],
method: 'POST',
path: '/orders',
request: {
body: OrdersCreateRequestBodySchema,
},
response: {
body: OrdersCreateResponseBodySchema,
},
},
destroy: {
method: 'DELETE',
path: '/orders/:id',
pathParams: OrdersDestroyPathParamsSchema,
},
index: {
method: 'GET',
path: '/orders',
request: {
query: OrdersIndexRequestQuerySchema,
},
response: {
body: OrdersIndexResponseBodySchema,
},
},
show: {
method: 'GET',
path: '/orders/:id',
pathParams: OrdersShowPathParamsSchema,
response: {
body: OrdersShowResponseBodySchema,
},
},
update: {
errors: [422],
method: 'PATCH',
path: '/orders/:id',
pathParams: OrdersUpdatePathParamsSchema,
request: {
body: OrdersUpdateRequestBodySchema,
},
response: {
body: OrdersUpdateResponseBodySchema,
},
},
} as const;
export interface OrdersOperationTree {
create: Operation<OrdersCreate>;
destroy: Operation<OrdersDestroy>;
index: Operation<OrdersIndex>;
show: Operation<OrdersShow>;
update: Operation<OrdersUpdate>;
}