Validation Errors
ActiveRecord validation errors captured and presented in a unified format
API Definition
config/apis/happy_zebra.rb
# frozen_string_literal: true
Apiwork::API.define '/happy_zebra' do
key_format :camel
export :openapi
export :apiwork
resources :users
resources :posts, only: %i[index]
resources :comments, only: %i[index]
endModels
app/models/happy_zebra/user.rb
# frozen_string_literal: true
module HappyZebra
class User < ApplicationRecord
has_many :posts, dependent: :destroy
has_one :profile, dependent: :destroy
accepts_nested_attributes_for :posts
accepts_nested_attributes_for :profile
validates :email, format: { with: /@/ }, presence: true
validates :username, length: { maximum: 20, minimum: 3 }, presence: true
validate :validate_username_differs_from_email
private
def validate_username_differs_from_email
return unless username.present? && email.present?
return unless username == email
errors.add(:base, :conflict)
end
end
endDatabase Table
| Column | Type | Nullable | Default |
|---|---|---|---|
| id | string | ||
| created_at | datetime | ||
| string | |||
| updated_at | datetime | ||
| username | string |
app/models/happy_zebra/profile.rb
# frozen_string_literal: true
module HappyZebra
class Profile < ApplicationRecord
belongs_to :user
validates :bio, length: { maximum: 500 }
end
endDatabase Table
| Column | Type | Nullable | Default |
|---|---|---|---|
| id | string | ||
| bio | text | ✓ | |
| created_at | datetime | ||
| updated_at | datetime | ||
| user_id | string | ||
| website | string | ✓ |
app/models/happy_zebra/post.rb
# frozen_string_literal: true
module HappyZebra
class Post < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
accepts_nested_attributes_for :comments
validates :title, length: { maximum: 100 }, presence: true
end
endDatabase Table
| Column | Type | Nullable | Default |
|---|---|---|---|
| id | string | ||
| created_at | datetime | ||
| title | string | ||
| updated_at | datetime | ||
| user_id | string |
app/models/happy_zebra/comment.rb
# frozen_string_literal: true
module HappyZebra
class Comment < ApplicationRecord
belongs_to :post
validates :body, length: { maximum: 500 }, presence: true
validates :author, presence: true
end
endDatabase Table
| Column | Type | Nullable | Default |
|---|---|---|---|
| id | string | ||
| author | string | ||
| body | string | ||
| created_at | datetime | ||
| post_id | string | ||
| updated_at | datetime |
Representations
app/representations/happy_zebra/user_representation.rb
# frozen_string_literal: true
module HappyZebra
class UserRepresentation < Apiwork::Representation::Base
attribute :id
attribute :email, filterable: true, writable: true
attribute :username, filterable: true, writable: true
attribute :created_at
attribute :updated_at
has_one :profile, include: :always, writable: true
has_many :posts, include: :always, writable: true
end
endapp/representations/happy_zebra/profile_representation.rb
# frozen_string_literal: true
module HappyZebra
class ProfileRepresentation < Apiwork::Representation::Base
attribute :id
attribute :bio, writable: true
attribute :website, writable: true
attribute :created_at
attribute :updated_at
belongs_to :user
end
endapp/representations/happy_zebra/post_representation.rb
# frozen_string_literal: true
module HappyZebra
class PostRepresentation < Apiwork::Representation::Base
attribute :id
attribute :title, writable: true
has_many :comments, include: :always, writable: true
end
endapp/representations/happy_zebra/comment_representation.rb
# frozen_string_literal: true
module HappyZebra
class CommentRepresentation < Apiwork::Representation::Base
attribute :id
attribute :body, writable: true
attribute :author, writable: true
end
endContracts
app/contracts/happy_zebra/user_contract.rb
# frozen_string_literal: true
module HappyZebra
class UserContract < Apiwork::Contract::Base
representation UserRepresentation
end
endapp/contracts/happy_zebra/post_contract.rb
# frozen_string_literal: true
module HappyZebra
class PostContract < Apiwork::Contract::Base
representation PostRepresentation
end
endapp/contracts/happy_zebra/comment_contract.rb
# frozen_string_literal: true
module HappyZebra
class CommentContract < Apiwork::Contract::Base
representation CommentRepresentation
end
endControllers
app/controllers/happy_zebra/users_controller.rb
# frozen_string_literal: true
module HappyZebra
class UsersController < ApplicationController
before_action :set_user, only: %i[show update destroy]
def index
users = User.all
expose users
end
def show
expose user
end
def create
user = User.create(contract.body[:user])
expose user
end
def update
user.update(contract.body[:user])
expose user
end
def destroy
user.destroy
expose user
end
private
attr_reader :user
def set_user
@user = User.find(params[:id])
end
end
endapp/controllers/happy_zebra/posts_controller.rb
# frozen_string_literal: true
module HappyZebra
class PostsController < ApplicationController
def index
posts = Post.all
expose posts
end
end
endapp/controllers/happy_zebra/comments_controller.rb
# frozen_string_literal: true
module HappyZebra
class CommentsController < ApplicationController
def index
comments = Comment.all
expose comments
end
end
endRequest Examples
Create valid user
Request
POST /happy_zebra/users
Content-Type: application/json
{
"user": {
"email": "john@example.com",
"username": "johndoe",
"profile": {
"OP": "create",
"bio": "Software developer",
"website": "https://example.com"
}
}
}Response 201
{
"user": {
"id": "571466c2-02cb-52cb-a9d1-7bd5f8e21034",
"email": "john@example.com",
"username": "johndoe",
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z",
"profile": {
"id": "c8f3124b-cf0c-55c4-b8e7-106c58c6a686",
"bio": "Software developer",
"website": "https://example.com",
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z"
},
"posts": []
}
}Invalid email format
Request
POST /happy_zebra/users
Content-Type: application/json
{
"user": {
"email": "not-an-email",
"username": "johndoe"
}
}Response 422
{
"issues": [
{
"code": "invalid",
"detail": "Invalid",
"meta": {},
"path": [
"user",
"email"
],
"pointer": "/user/email"
}
],
"layer": "domain"
}Empty required fields
Request
POST /happy_zebra/users
Content-Type: application/json
{
"user": {
"email": "",
"username": ""
}
}Response 422
{
"issues": [
{
"code": "invalid",
"detail": "Invalid",
"meta": {},
"path": [
"user",
"email"
],
"pointer": "/user/email"
},
{
"code": "required",
"detail": "Required",
"meta": {},
"path": [
"user",
"email"
],
"pointer": "/user/email"
},
{
"code": "min",
"detail": "Too short",
"meta": {
"min": 3
},
"path": [
"user",
"username"
],
"pointer": "/user/username"
},
{
"code": "required",
"detail": "Required",
"meta": {},
"path": [
"user",
"username"
],
"pointer": "/user/username"
}
],
"layer": "domain"
}Invalid nested profile
Request
POST /happy_zebra/users
Content-Type: application/json
{
"user": {
"email": "john@example.com",
"username": "johndoe",
"profile": {
"OP": "create",
"bio": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Extra text to push this well over the five hundred character limit that exists."
}
}
}Response 422
{
"issues": [
{
"code": "max",
"detail": "Too long",
"meta": {
"max": 500
},
"path": [
"user",
"profile",
"bio"
],
"pointer": "/user/profile/bio"
}
],
"layer": "domain"
}Create with deep nesting
Request
POST /happy_zebra/users
Content-Type: application/json
{
"user": {
"email": "deep@example.com",
"username": "deepuser",
"posts": [
{
"OP": "create",
"title": "My First Post",
"comments": [
{
"OP": "create",
"body": "Great post!",
"author": "Jane"
},
{
"OP": "create",
"body": "Thanks for sharing",
"author": "Bob"
}
]
}
]
}
}Response 201
{
"user": {
"id": "571466c2-02cb-52cb-a9d1-7bd5f8e21034",
"email": "deep@example.com",
"username": "deepuser",
"createdAt": "2026-04-01T12:00:00.000Z",
"updatedAt": "2026-04-01T12:00:00.000Z",
"profile": null,
"posts": [
{
"id": "f79aecb1-8fa0-5c07-8478-508eb2320f28",
"title": "My First Post",
"comments": [
{
"id": "59e8d0c6-28d3-518c-a286-d8e2dd65062a",
"body": "Great post!",
"author": "Jane"
},
{
"id": "f3484847-e838-513d-8b33-1dd8a97dcb44",
"body": "Thanks for sharing",
"author": "Bob"
}
]
}
]
}
}Custom base error
Request
POST /happy_zebra/users
Content-Type: application/json
{
"user": {
"email": "same@example.com",
"username": "same@example.com"
}
}Response 422
{
"issues": [
{
"code": "conflict",
"detail": "Conflict",
"meta": {},
"path": [
"user"
],
"pointer": "/user"
}
],
"layer": "domain"
}Deep nested validation error
Request
POST /happy_zebra/users
Content-Type: application/json
{
"user": {
"email": "deep@example.com",
"username": "deepuser",
"posts": [
{
"OP": "create",
"title": "My Post",
"comments": [
{
"OP": "create",
"body": "",
"author": ""
}
]
}
]
}
}Response 422
{
"issues": [
{
"code": "required",
"detail": "Required",
"meta": {},
"path": [
"user",
"posts",
0,
"comments",
0,
"body"
],
"pointer": "/user/posts/0/comments/0/body"
},
{
"code": "required",
"detail": "Required",
"meta": {},
"path": [
"user",
"posts",
0,
"comments",
0,
"author"
],
"pointer": "/user/posts/0/comments/0/author"
}
],
"layer": "domain"
}Exports
OpenAPI
---
openapi: 3.1.0
info:
title: "/happy_zebra"
version: 1.0.0
paths:
"/users":
get:
operationId: usersIndex
parameters:
- in: query
name: filter
required: false
schema:
oneOf:
- "$ref": "#/components/schemas/userFilter"
- items:
"$ref": "#/components/schemas/userFilter"
type: array
- in: query
name: include
required: false
schema:
"$ref": "#/components/schemas/userInclude"
- in: query
name: page
required: false
schema:
"$ref": "#/components/schemas/userPage"
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
pagination:
"$ref": "#/components/schemas/offsetPagination"
users:
items:
"$ref": "#/components/schemas/user"
type: array
type: object
required:
- pagination
- users
description: ''
post:
operationId: usersCreate
parameters:
- in: query
name: include
required: false
schema:
"$ref": "#/components/schemas/userInclude"
requestBody:
content:
application/json:
schema:
properties:
user:
"$ref": "#/components/schemas/userCreatePayload"
type: object
required:
- user
required: true
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
user:
"$ref": "#/components/schemas/user"
type: object
required:
- user
description: ''
'422':
description: Unprocessable Entity
content:
application/json:
schema:
properties:
issues:
items:
"$ref": "#/components/schemas/error"
type: array
required:
- issues
type: object
"/users/{id}":
get:
operationId: usersShow
parameters:
- in: path
name: id
required: true
schema:
type: string
- in: query
name: include
required: false
schema:
"$ref": "#/components/schemas/userInclude"
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
user:
"$ref": "#/components/schemas/user"
type: object
required:
- user
description: ''
patch:
operationId: usersUpdate
parameters:
- in: path
name: id
required: true
schema:
type: string
- in: query
name: include
required: false
schema:
"$ref": "#/components/schemas/userInclude"
requestBody:
content:
application/json:
schema:
properties:
user:
"$ref": "#/components/schemas/userUpdatePayload"
type: object
required:
- user
required: true
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
user:
"$ref": "#/components/schemas/user"
type: object
required:
- user
description: ''
'422':
description: Unprocessable Entity
content:
application/json:
schema:
properties:
issues:
items:
"$ref": "#/components/schemas/error"
type: array
required:
- issues
type: object
delete:
operationId: usersDestroy
parameters:
- in: path
name: id
required: true
schema:
type: string
- in: query
name: include
required: false
schema:
"$ref": "#/components/schemas/userInclude"
responses:
'204':
description: ''
"/posts":
get:
operationId: postsIndex
parameters:
- in: query
name: page
required: false
schema:
"$ref": "#/components/schemas/postPage"
responses:
'200':
content:
application/json:
schema:
properties:
meta:
properties: {}
type: object
pagination:
"$ref": "#/components/schemas/offsetPagination"
posts:
items:
"$ref": "#/components/schemas/post"
type: array
type: object
required:
- pagination
- posts
description: ''
"/comments":
get:
operationId: commentsIndex
parameters:
- in: query
name: page
required: false
schema:
"$ref": "#/components/schemas/commentPage"
responses:
'200':
content:
application/json:
schema:
properties:
comments:
items:
"$ref": "#/components/schemas/comment"
type: array
meta:
properties: {}
type: object
pagination:
"$ref": "#/components/schemas/offsetPagination"
type: object
required:
- comments
- pagination
description: ''
components:
schemas:
comment:
properties:
author:
type: string
body:
type: string
id:
type: string
type: object
required:
- author
- body
- id
commentNestedCreatePayload:
properties:
OP:
const: create
type: string
author:
type: string
body:
type: string
type: object
required:
- OP
- author
- body
commentNestedDeletePayload:
properties:
OP:
const: delete
type: string
id:
type: string
type: object
required:
- OP
- id
commentNestedPayload:
oneOf:
- "$ref": "#/components/schemas/commentNestedCreatePayload"
- "$ref": "#/components/schemas/commentNestedUpdatePayload"
- "$ref": "#/components/schemas/commentNestedDeletePayload"
discriminator:
mapping:
create: "#/components/schemas/commentNestedCreatePayload"
update: "#/components/schemas/commentNestedUpdatePayload"
delete: "#/components/schemas/commentNestedDeletePayload"
propertyName: OP
commentNestedUpdatePayload:
properties:
OP:
const: update
type: string
author:
type: string
body:
type: string
id:
type: string
type: object
required:
- OP
commentPage:
properties:
number:
type: integer
minimum: 1
size:
type: integer
minimum: 1
maximum: 100
type: object
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
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
post:
properties:
comments:
items:
"$ref": "#/components/schemas/comment"
type: array
id:
type: string
title:
type: string
type: object
required:
- comments
- id
- title
postNestedCreatePayload:
properties:
OP:
const: create
type: string
comments:
items:
"$ref": "#/components/schemas/commentNestedPayload"
type: array
title:
type: string
type: object
required:
- OP
- title
postNestedDeletePayload:
properties:
OP:
const: delete
type: string
id:
type: string
type: object
required:
- OP
- id
postNestedPayload:
oneOf:
- "$ref": "#/components/schemas/postNestedCreatePayload"
- "$ref": "#/components/schemas/postNestedUpdatePayload"
- "$ref": "#/components/schemas/postNestedDeletePayload"
discriminator:
mapping:
create: "#/components/schemas/postNestedCreatePayload"
update: "#/components/schemas/postNestedUpdatePayload"
delete: "#/components/schemas/postNestedDeletePayload"
propertyName: OP
postNestedUpdatePayload:
properties:
OP:
const: update
type: string
comments:
items:
"$ref": "#/components/schemas/commentNestedPayload"
type: array
id:
type: string
title:
type: string
type: object
required:
- OP
postPage:
properties:
number:
type: integer
minimum: 1
size:
type: integer
minimum: 1
maximum: 100
type: object
profile:
properties:
bio:
type:
- string
- 'null'
createdAt:
type: string
format: date-time
id:
type: string
updatedAt:
type: string
format: date-time
user:
"$ref": "#/components/schemas/user"
website:
type:
- string
- 'null'
type: object
required:
- bio
- createdAt
- id
- updatedAt
- website
profileInclude:
properties:
user:
type: boolean
type: object
profileNestedCreatePayload:
properties:
OP:
const: create
type: string
bio:
type:
- string
- 'null'
default:
website:
type:
- string
- 'null'
default:
type: object
required:
- OP
profileNestedDeletePayload:
properties:
OP:
const: delete
type: string
id:
type: string
type: object
required:
- OP
- id
profileNestedPayload:
oneOf:
- "$ref": "#/components/schemas/profileNestedCreatePayload"
- "$ref": "#/components/schemas/profileNestedUpdatePayload"
- "$ref": "#/components/schemas/profileNestedDeletePayload"
discriminator:
mapping:
create: "#/components/schemas/profileNestedCreatePayload"
update: "#/components/schemas/profileNestedUpdatePayload"
delete: "#/components/schemas/profileNestedDeletePayload"
propertyName: OP
profileNestedUpdatePayload:
properties:
OP:
const: update
type: string
bio:
type:
- string
- 'null'
id:
type: string
website:
type:
- string
- 'null'
type: object
required:
- OP
stringFilter:
properties:
contains:
type: string
endsWith:
type: string
eq:
type: string
in:
items:
type: string
type: array
startsWith:
type: string
type: object
user:
properties:
createdAt:
type: string
format: date-time
email:
type: string
id:
type: string
posts:
items:
"$ref": "#/components/schemas/post"
type: array
profile:
"$ref": "#/components/schemas/profile"
updatedAt:
type: string
format: date-time
username:
type: string
type: object
required:
- createdAt
- email
- id
- posts
- profile
- updatedAt
- username
userCreatePayload:
properties:
email:
type: string
posts:
items:
"$ref": "#/components/schemas/postNestedPayload"
type: array
profile:
"$ref": "#/components/schemas/profileNestedPayload"
username:
type: string
type: object
required:
- email
- username
userFilter:
properties:
AND:
items:
"$ref": "#/components/schemas/userFilter"
type: array
NOT:
"$ref": "#/components/schemas/userFilter"
OR:
items:
"$ref": "#/components/schemas/userFilter"
type: array
email:
oneOf:
- type: string
- "$ref": "#/components/schemas/stringFilter"
username:
oneOf:
- type: string
- "$ref": "#/components/schemas/stringFilter"
type: object
userInclude:
properties:
profile:
"$ref": "#/components/schemas/profileInclude"
type: object
userPage:
properties:
number:
type: integer
minimum: 1
size:
type: integer
minimum: 1
maximum: 100
type: object
userUpdatePayload:
properties:
email:
type: string
posts:
items:
"$ref": "#/components/schemas/postNestedPayload"
type: array
profile:
"$ref": "#/components/schemas/profileNestedPayload"
username:
type: string
type: objectApiwork
{
"base_path": "/happy_zebra",
"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": "dd110a4ef0a4a1fb",
"info": null,
"locales": [],
"resources": [
{
"actions": [
{
"name": "users.index",
"deprecated": false,
"description": null,
"method": "get",
"operation_id": null,
"path": "/users",
"raises": [],
"request": {
"body": [],
"description": null,
"query": [
{
"name": "filter",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "union",
"discriminator": "",
"variants": [
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "user_filter"
},
{
"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": "user_filter"
}
}
]
},
{
"name": "include",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "user_include"
},
{
"name": "page",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "user_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": "pagination",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "offset_pagination"
},
{
"name": "users",
"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": "user"
}
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
},
{
"name": "users.show",
"deprecated": false,
"description": null,
"method": "get",
"operation_id": null,
"path": "/users/:id",
"raises": [],
"request": {
"body": [],
"description": null,
"query": [
{
"name": "include",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "user_include"
}
]
},
"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": "user",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "user"
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
},
{
"name": "users.create",
"deprecated": false,
"description": null,
"method": "post",
"operation_id": null,
"path": "/users",
"raises": [
"unprocessable_entity"
],
"request": {
"body": [
{
"name": "user",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "user_create_payload"
}
],
"description": null,
"query": [
{
"name": "include",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "user_include"
}
]
},
"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": "user",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "user"
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
},
{
"name": "users.update",
"deprecated": false,
"description": null,
"method": "patch",
"operation_id": null,
"path": "/users/:id",
"raises": [
"unprocessable_entity"
],
"request": {
"body": [
{
"name": "user",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "user_update_payload"
}
],
"description": null,
"query": [
{
"name": "include",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "user_include"
}
]
},
"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": "user",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "user"
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
},
{
"name": "users.destroy",
"deprecated": false,
"description": null,
"method": "delete",
"operation_id": null,
"path": "/users/:id",
"raises": [],
"request": {
"body": [],
"description": null,
"query": [
{
"name": "include",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "user_include"
}
]
},
"response": {
"body": null,
"description": null,
"no_content": true
},
"summary": null,
"tags": []
}
],
"identifier": "users",
"name": "users",
"parent_identifiers": [],
"path": "users",
"resources": [],
"scope": "user"
},
{
"actions": [
{
"name": "posts.index",
"deprecated": false,
"description": null,
"method": "get",
"operation_id": null,
"path": "/posts",
"raises": [],
"request": {
"body": [],
"description": null,
"query": [
{
"name": "page",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "post_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": "pagination",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "offset_pagination"
},
{
"name": "posts",
"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": "post"
}
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
}
],
"identifier": "posts",
"name": "posts",
"parent_identifiers": [],
"path": "posts",
"resources": [],
"scope": "post"
},
{
"actions": [
{
"name": "comments.index",
"deprecated": false,
"description": null,
"method": "get",
"operation_id": null,
"path": "/comments",
"raises": [],
"request": {
"body": [],
"description": null,
"query": [
{
"name": "page",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "comment_page"
}
]
},
"response": {
"body": {
"deprecated": null,
"description": null,
"nullable": null,
"optional": null,
"type": "object",
"partial": null,
"shape": [
{
"name": "comments",
"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": "comment"
}
},
{
"name": "meta",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "object",
"partial": false,
"shape": []
},
{
"name": "pagination",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "offset_pagination"
}
]
},
"description": null,
"no_content": false
},
"summary": null,
"tags": []
}
],
"identifier": "comments",
"name": "comments",
"parent_identifiers": [],
"path": "comments",
"resources": [],
"scope": "comment"
}
],
"types": [
{
"recursive": true,
"deprecated": false,
"description": null,
"example": null,
"name": "profile",
"scope": "profile",
"type": "object",
"extends": [],
"shape": [
{
"name": "bio",
"deprecated": false,
"description": null,
"nullable": true,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"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": "updatedAt",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "datetime",
"example": null
},
{
"name": "user",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "user"
},
{
"name": "website",
"deprecated": false,
"description": null,
"nullable": true,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": true,
"deprecated": false,
"description": null,
"example": null,
"name": "user_filter",
"scope": "user",
"type": "object",
"extends": [],
"shape": [
{
"name": "AND",
"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": "user_filter"
}
},
{
"name": "NOT",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "user_filter"
},
{
"name": "OR",
"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": "user_filter"
}
},
{
"name": "email",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"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": "reference",
"reference": "string_filter"
}
]
},
{
"name": "username",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"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": "reference",
"reference": "string_filter"
}
]
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "comment",
"scope": "comment",
"type": "object",
"extends": [],
"shape": [
{
"name": "author",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "body",
"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
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "comment_nested_create_payload",
"scope": "comment",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "create"
},
{
"name": "author",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "body",
"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": "comment_nested_delete_payload",
"scope": "comment",
"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": "comment_nested_update_payload",
"scope": "comment",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "update"
},
{
"name": "author",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "body",
"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
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "comment_page",
"scope": "comment",
"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": "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": "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": "post_nested_delete_payload",
"scope": "post",
"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": "post_page",
"scope": "post",
"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": "profile_include",
"scope": "profile",
"type": "object",
"extends": [],
"shape": [
{
"name": "user",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "boolean",
"example": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "profile_nested_create_payload",
"scope": "profile",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "create"
},
{
"name": "bio",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "string",
"default": null,
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "website",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "string",
"default": null,
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "profile_nested_delete_payload",
"scope": "profile",
"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": "profile_nested_update_payload",
"scope": "profile",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "update"
},
{
"name": "bio",
"deprecated": false,
"description": null,
"nullable": true,
"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": "website",
"deprecated": false,
"description": null,
"nullable": true,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "string_filter",
"scope": null,
"type": "object",
"extends": [],
"shape": [
{
"name": "contains",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "endsWith",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "eq",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "in",
"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": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
},
{
"name": "startsWith",
"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": "user_page",
"scope": "user",
"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": "comment_nested_payload",
"scope": "comment",
"type": "union",
"discriminator": "OP",
"variants": [
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "comment_nested_create_payload",
"tag": "create"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "comment_nested_update_payload",
"tag": "update"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "comment_nested_delete_payload",
"tag": "delete"
}
]
},
{
"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": "post",
"scope": "post",
"type": "object",
"extends": [],
"shape": [
{
"name": "comments",
"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": "comment"
}
},
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "title",
"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": "profile_nested_payload",
"scope": "profile",
"type": "union",
"discriminator": "OP",
"variants": [
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "profile_nested_create_payload",
"tag": "create"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "profile_nested_update_payload",
"tag": "update"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "profile_nested_delete_payload",
"tag": "delete"
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "user_include",
"scope": "user",
"type": "object",
"extends": [],
"shape": [
{
"name": "profile",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "profile_include"
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "post_nested_create_payload",
"scope": "post",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "create"
},
{
"name": "comments",
"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": "comment_nested_payload"
}
},
{
"name": "title",
"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": "post_nested_update_payload",
"scope": "post",
"type": "object",
"extends": [],
"shape": [
{
"name": "OP",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "literal",
"value": "update"
},
{
"name": "comments",
"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": "comment_nested_payload"
}
},
{
"name": "id",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "title",
"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": "user",
"scope": "user",
"type": "object",
"extends": [],
"shape": [
{
"name": "createdAt",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "datetime",
"example": null
},
{
"name": "email",
"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": "posts",
"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": "post"
}
},
{
"name": "profile",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "profile"
},
{
"name": "updatedAt",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "datetime",
"example": null
},
{
"name": "username",
"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": "post_nested_payload",
"scope": "post",
"type": "union",
"discriminator": "OP",
"variants": [
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "post_nested_create_payload",
"tag": "create"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "post_nested_update_payload",
"tag": "update"
},
{
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "post_nested_delete_payload",
"tag": "delete"
}
]
},
{
"recursive": false,
"deprecated": false,
"description": null,
"example": null,
"name": "user_create_payload",
"scope": "user",
"type": "object",
"extends": [],
"shape": [
{
"name": "email",
"deprecated": false,
"description": null,
"nullable": false,
"optional": false,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "posts",
"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": "post_nested_payload"
}
},
{
"name": "profile",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "profile_nested_payload"
},
{
"name": "username",
"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": "user_update_payload",
"scope": "user",
"type": "object",
"extends": [],
"shape": [
{
"name": "email",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
},
{
"name": "posts",
"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": "post_nested_payload"
}
},
{
"name": "profile",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "reference",
"reference": "profile_nested_payload"
},
{
"name": "username",
"deprecated": false,
"description": null,
"nullable": false,
"optional": true,
"type": "string",
"example": null,
"format": null,
"max": null,
"min": null
}
]
}
]
}Codegen
TypeScript
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 StringFilter {
contains?: string;
endsWith?: string;
eq?: string;
in?: string[];
startsWith?: string;
}
export interface Error {
issues: ErrorIssue[];
layer: ErrorLayer;
}export interface Comment {
author: string;
body: string;
id: string;
}
export interface CommentNestedCreatePayload {
author: string;
body: string;
OP: 'create';
}
export interface CommentNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface CommentNestedUpdatePayload {
author?: string;
body?: string;
id?: string;
OP: 'update';
}
export interface CommentPage {
number?: number;
size?: number;
}
export type CommentNestedPayload =
| (CommentNestedCreatePayload & { OP: 'create' })
| (CommentNestedUpdatePayload & { OP: 'update' })
| (CommentNestedDeletePayload & { OP: 'delete' });export * from './comment';
export * from './post';
export * from './profile';
export * from './user';import type { Comment, CommentNestedPayload } from './comment';
export interface PostNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface PostPage {
number?: number;
size?: number;
}
export interface Post {
comments: Comment[];
id: string;
title: string;
}
export interface PostNestedCreatePayload {
comments?: CommentNestedPayload[];
OP: 'create';
title: string;
}
export interface PostNestedUpdatePayload {
comments?: CommentNestedPayload[];
id?: string;
OP: 'update';
title?: string;
}
export type PostNestedPayload =
| (PostNestedCreatePayload & { OP: 'create' })
| (PostNestedUpdatePayload & { OP: 'update' })
| (PostNestedDeletePayload & { OP: 'delete' });import type { User } from './user';
export interface Profile {
bio: string | null;
createdAt: string;
id: string;
updatedAt: string;
user?: User;
website: string | null;
}
export interface ProfileInclude {
user?: boolean;
}
export interface ProfileNestedCreatePayload {
bio?: string | null;
OP: 'create';
website?: string | null;
}
export interface ProfileNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface ProfileNestedUpdatePayload {
bio?: string | null;
id?: string;
OP: 'update';
website?: string | null;
}
export type ProfileNestedPayload =
| (ProfileNestedCreatePayload & { OP: 'create' })
| (ProfileNestedUpdatePayload & { OP: 'update' })
| (ProfileNestedDeletePayload & { OP: 'delete' });import type { StringFilter } from '../api';
import type { Post, PostNestedPayload } from './post';
import type { Profile, ProfileInclude, ProfileNestedPayload } from './profile';
export interface UserFilter {
AND?: UserFilter[];
email?: string | StringFilter;
NOT?: UserFilter;
OR?: UserFilter[];
username?: string | StringFilter;
}
export interface UserPage {
number?: number;
size?: number;
}
export interface UserInclude {
profile?: ProfileInclude;
}
export interface User {
createdAt: string;
email: string;
id: string;
posts: Post[];
profile: Profile;
updatedAt: string;
username: string;
}
export interface UserCreatePayload {
email: string;
posts?: PostNestedPayload[];
profile?: ProfileNestedPayload;
username: string;
}
export interface UserUpdatePayload {
email?: string;
posts?: PostNestedPayload[];
profile?: ProfileNestedPayload;
username?: string;
}import type { OffsetPagination } from '../api';
import type { Comment, CommentPage } from '../domains/comment';
export type CommentsIndexMethod = 'GET';
export type CommentsIndexPath = '/comments';
export interface CommentsIndexRequestQuery {
page?: CommentPage;
}
export type CommentsIndexResponseBody = {
comments: Comment[];
meta?: Record<string, unknown>;
pagination: OffsetPagination;
};
export interface CommentsIndexRequest {
query: CommentsIndexRequestQuery;
}
export interface CommentsIndexResponse {
body: CommentsIndexResponseBody;
}
export interface CommentsIndex {
method: CommentsIndexMethod;
path: CommentsIndexPath;
request: CommentsIndexRequest;
response: CommentsIndexResponse;
}export * from './comments';
export * from './posts';
export * from './users';import type { OffsetPagination } from '../api';
import type { Post, PostPage } from '../domains/post';
export type PostsIndexMethod = 'GET';
export type PostsIndexPath = '/posts';
export interface PostsIndexRequestQuery {
page?: PostPage;
}
export type PostsIndexResponseBody = {
meta?: Record<string, unknown>;
pagination: OffsetPagination;
posts: Post[];
};
export interface PostsIndexRequest {
query: PostsIndexRequestQuery;
}
export interface PostsIndexResponse {
body: PostsIndexResponseBody;
}
export interface PostsIndex {
method: PostsIndexMethod;
path: PostsIndexPath;
request: PostsIndexRequest;
response: PostsIndexResponse;
}import type { OffsetPagination } from '../api';
import type {
User,
UserCreatePayload,
UserFilter,
UserInclude,
UserPage,
UserUpdatePayload,
} from '../domains/user';
export type UsersIndexMethod = 'GET';
export type UsersIndexPath = '/users';
export interface UsersIndexRequestQuery {
filter?: UserFilter | UserFilter[];
include?: UserInclude;
page?: UserPage;
}
export type UsersIndexResponseBody = {
meta?: Record<string, unknown>;
pagination: OffsetPagination;
users: User[];
};
export interface UsersIndexRequest {
query: UsersIndexRequestQuery;
}
export interface UsersIndexResponse {
body: UsersIndexResponseBody;
}
export interface UsersIndex {
method: UsersIndexMethod;
path: UsersIndexPath;
request: UsersIndexRequest;
response: UsersIndexResponse;
}
export type UsersShowMethod = 'GET';
export type UsersShowPath = '/users/:id';
export interface UsersShowPathParams {
id: string;
}
export interface UsersShowRequestQuery {
include?: UserInclude;
}
export type UsersShowResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersShowRequest {
query: UsersShowRequestQuery;
}
export interface UsersShowResponse {
body: UsersShowResponseBody;
}
export interface UsersShow {
method: UsersShowMethod;
path: UsersShowPath;
pathParams: UsersShowPathParams;
request: UsersShowRequest;
response: UsersShowResponse;
}
export type UsersCreateMethod = 'POST';
export type UsersCreatePath = '/users';
export interface UsersCreateRequestQuery {
include?: UserInclude;
}
export interface UsersCreateRequestBody {
user: UserCreatePayload;
}
export type UsersCreateResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersCreateRequest {
body: UsersCreateRequestBody;
query: UsersCreateRequestQuery;
}
export interface UsersCreateResponse {
body: UsersCreateResponseBody;
}
export type UsersCreateErrors = 422;
export interface UsersCreate {
errors: UsersCreateErrors;
method: UsersCreateMethod;
path: UsersCreatePath;
request: UsersCreateRequest;
response: UsersCreateResponse;
}
export type UsersUpdateMethod = 'PATCH';
export type UsersUpdatePath = '/users/:id';
export interface UsersUpdatePathParams {
id: string;
}
export interface UsersUpdateRequestQuery {
include?: UserInclude;
}
export interface UsersUpdateRequestBody {
user: UserUpdatePayload;
}
export type UsersUpdateResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersUpdateRequest {
body: UsersUpdateRequestBody;
query: UsersUpdateRequestQuery;
}
export interface UsersUpdateResponse {
body: UsersUpdateResponseBody;
}
export type UsersUpdateErrors = 422;
export interface UsersUpdate {
errors: UsersUpdateErrors;
method: UsersUpdateMethod;
path: UsersUpdatePath;
pathParams: UsersUpdatePathParams;
request: UsersUpdateRequest;
response: UsersUpdateResponse;
}
export type UsersDestroyMethod = 'DELETE';
export type UsersDestroyPath = '/users/:id';
export interface UsersDestroyPathParams {
id: string;
}
export interface UsersDestroyRequestQuery {
include?: UserInclude;
}
export interface UsersDestroyRequest {
query: UsersDestroyRequestQuery;
}
export interface UsersDestroy {
method: UsersDestroyMethod;
path: UsersDestroyPath;
pathParams: UsersDestroyPathParams;
request: UsersDestroyRequest;
}Zod
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 StringFilterSchema = z.object({
contains: z.string().optional(),
endsWith: z.string().optional(),
eq: z.string().optional(),
in: z.array(z.string()).optional(),
startsWith: z.string().optional(),
});
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 StringFilter {
contains?: string;
endsWith?: string;
eq?: string;
in?: string[];
startsWith?: string;
}
export interface Error {
issues: ErrorIssue[];
layer: ErrorLayer;
}import * as z from 'zod';
export const CommentSchema = z.object({
author: z.string(),
body: z.string(),
id: z.string(),
});
export const CommentNestedCreatePayloadSchema = z.object({
author: z.string(),
body: z.string(),
OP: z.literal('create'),
});
export const CommentNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const CommentNestedUpdatePayloadSchema = z.object({
author: z.string().optional(),
body: z.string().optional(),
id: z.string().optional(),
OP: z.literal('update'),
});
export const CommentPageSchema = z.object({
number: z.number().int().min(1).optional(),
size: z.number().int().min(1).max(100).optional(),
});
export const CommentNestedPayloadSchema = z.discriminatedUnion('OP', [
CommentNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
CommentNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
CommentNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface Comment {
author: string;
body: string;
id: string;
}
export interface CommentNestedCreatePayload {
author: string;
body: string;
OP: 'create';
}
export interface CommentNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface CommentNestedUpdatePayload {
author?: string;
body?: string;
id?: string;
OP: 'update';
}
export interface CommentPage {
number?: number;
size?: number;
}
export type CommentNestedPayload =
| (CommentNestedCreatePayload & { OP: 'create' })
| (CommentNestedUpdatePayload & { OP: 'update' })
| (CommentNestedDeletePayload & { OP: 'delete' });export * from './comment';
export * from './post';
export * from './profile';
export * from './user';import type { Comment, CommentNestedPayload } from './comment';
import * as z from 'zod';
import { CommentNestedPayloadSchema, CommentSchema } from './comment';
export const PostNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const PostPageSchema = z.object({
number: z.number().int().min(1).optional(),
size: z.number().int().min(1).max(100).optional(),
});
export const PostSchema = z.object({
comments: z.array(CommentSchema),
id: z.string(),
title: z.string(),
});
export const PostNestedCreatePayloadSchema = z.object({
comments: z.array(CommentNestedPayloadSchema).optional(),
OP: z.literal('create'),
title: z.string(),
});
export const PostNestedUpdatePayloadSchema = z.object({
comments: z.array(CommentNestedPayloadSchema).optional(),
id: z.string().optional(),
OP: z.literal('update'),
title: z.string().optional(),
});
export const PostNestedPayloadSchema = z.discriminatedUnion('OP', [
PostNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
PostNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
PostNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface PostNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface PostPage {
number?: number;
size?: number;
}
export interface Post {
comments: Comment[];
id: string;
title: string;
}
export interface PostNestedCreatePayload {
comments?: CommentNestedPayload[];
OP: 'create';
title: string;
}
export interface PostNestedUpdatePayload {
comments?: CommentNestedPayload[];
id?: string;
OP: 'update';
title?: string;
}
export type PostNestedPayload =
| (PostNestedCreatePayload & { OP: 'create' })
| (PostNestedUpdatePayload & { OP: 'update' })
| (PostNestedDeletePayload & { OP: 'delete' });import type { User } from './user';
import * as z from 'zod';
import { UserSchema } from './user';
export const ProfileSchema: z.ZodType<Profile> = z.lazy(() =>
z.object({
bio: z.string().nullable(),
createdAt: z.iso.datetime(),
id: z.string(),
updatedAt: z.iso.datetime(),
user: UserSchema.optional(),
website: z.string().nullable(),
}),
);
export const ProfileIncludeSchema = z.object({
user: z.boolean().optional(),
});
export const ProfileNestedCreatePayloadSchema = z.object({
bio: z.string().nullable().default(null),
OP: z.literal('create'),
website: z.string().nullable().default(null),
});
export const ProfileNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const ProfileNestedUpdatePayloadSchema = z.object({
bio: z.string().nullable().optional(),
id: z.string().optional(),
OP: z.literal('update'),
website: z.string().nullable().optional(),
});
export const ProfileNestedPayloadSchema = z.discriminatedUnion('OP', [
ProfileNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
ProfileNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
ProfileNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface Profile {
bio: string | null;
createdAt: string;
id: string;
updatedAt: string;
user?: User;
website: string | null;
}
export interface ProfileInclude {
user?: boolean;
}
export interface ProfileNestedCreatePayload {
bio?: string | null;
OP: 'create';
website?: string | null;
}
export interface ProfileNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface ProfileNestedUpdatePayload {
bio?: string | null;
id?: string;
OP: 'update';
website?: string | null;
}
export type ProfileNestedPayload =
| (ProfileNestedCreatePayload & { OP: 'create' })
| (ProfileNestedUpdatePayload & { OP: 'update' })
| (ProfileNestedDeletePayload & { OP: 'delete' });import type { StringFilter } from '../api';
import type { Post, PostNestedPayload } from './post';
import type { Profile, ProfileInclude, ProfileNestedPayload } from './profile';
import * as z from 'zod';
import { StringFilterSchema } from '../api';
import { PostNestedPayloadSchema, PostSchema } from './post';
import {
ProfileIncludeSchema,
ProfileNestedPayloadSchema,
ProfileSchema,
} from './profile';
export const UserFilterSchema: z.ZodType<UserFilter> = z.lazy(() =>
z.object({
AND: z.array(UserFilterSchema).optional(),
email: z.union([z.string(), StringFilterSchema]).optional(),
NOT: UserFilterSchema.optional(),
OR: z.array(UserFilterSchema).optional(),
username: z.union([z.string(), StringFilterSchema]).optional(),
}),
);
export const UserPageSchema = z.object({
number: z.number().int().min(1).optional(),
size: z.number().int().min(1).max(100).optional(),
});
export const UserIncludeSchema = z.object({
profile: ProfileIncludeSchema.optional(),
});
export const UserSchema = z.object({
createdAt: z.iso.datetime(),
email: z.string(),
id: z.string(),
posts: z.array(PostSchema),
profile: ProfileSchema,
updatedAt: z.iso.datetime(),
username: z.string(),
});
export const UserCreatePayloadSchema = z.object({
email: z.string(),
posts: z.array(PostNestedPayloadSchema).optional(),
profile: ProfileNestedPayloadSchema.optional(),
username: z.string(),
});
export const UserUpdatePayloadSchema = z.object({
email: z.string().optional(),
posts: z.array(PostNestedPayloadSchema).optional(),
profile: ProfileNestedPayloadSchema.optional(),
username: z.string().optional(),
});
export interface UserFilter {
AND?: UserFilter[];
email?: string | StringFilter;
NOT?: UserFilter;
OR?: UserFilter[];
username?: string | StringFilter;
}
export interface UserPage {
number?: number;
size?: number;
}
export interface UserInclude {
profile?: ProfileInclude;
}
export interface User {
createdAt: string;
email: string;
id: string;
posts: Post[];
profile: Profile;
updatedAt: string;
username: string;
}
export interface UserCreatePayload {
email: string;
posts?: PostNestedPayload[];
profile?: ProfileNestedPayload;
username: string;
}
export interface UserUpdatePayload {
email?: string;
posts?: PostNestedPayload[];
profile?: ProfileNestedPayload;
username?: string;
}import type { OffsetPagination } from '../api';
import type { Comment, CommentPage } from '../domains/comment';
import * as z from 'zod';
import { OffsetPaginationSchema } from '../api';
import { CommentPageSchema, CommentSchema } from '../domains/comment';
export const CommentsIndexRequestQuerySchema = z.object({
page: CommentPageSchema.optional(),
});
export const CommentsIndexResponseBodySchema = z.object({
comments: z.array(CommentSchema),
meta: z.record(z.string(), z.unknown()).optional(),
pagination: OffsetPaginationSchema,
});
export type CommentsIndexMethod = 'GET';
export type CommentsIndexPath = '/comments';
export interface CommentsIndexRequestQuery {
page?: CommentPage;
}
export type CommentsIndexResponseBody = {
comments: Comment[];
meta?: Record<string, unknown>;
pagination: OffsetPagination;
};
export interface CommentsIndexRequest {
query: CommentsIndexRequestQuery;
}
export interface CommentsIndexResponse {
body: CommentsIndexResponseBody;
}
export interface CommentsIndex {
method: CommentsIndexMethod;
path: CommentsIndexPath;
request: CommentsIndexRequest;
response: CommentsIndexResponse;
}export * from './comments';
export * from './posts';
export * from './users';import type { OffsetPagination } from '../api';
import type { Post, PostPage } from '../domains/post';
import * as z from 'zod';
import { OffsetPaginationSchema } from '../api';
import { PostPageSchema, PostSchema } from '../domains/post';
export const PostsIndexRequestQuerySchema = z.object({
page: PostPageSchema.optional(),
});
export const PostsIndexResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
pagination: OffsetPaginationSchema,
posts: z.array(PostSchema),
});
export type PostsIndexMethod = 'GET';
export type PostsIndexPath = '/posts';
export interface PostsIndexRequestQuery {
page?: PostPage;
}
export type PostsIndexResponseBody = {
meta?: Record<string, unknown>;
pagination: OffsetPagination;
posts: Post[];
};
export interface PostsIndexRequest {
query: PostsIndexRequestQuery;
}
export interface PostsIndexResponse {
body: PostsIndexResponseBody;
}
export interface PostsIndex {
method: PostsIndexMethod;
path: PostsIndexPath;
request: PostsIndexRequest;
response: PostsIndexResponse;
}import type { OffsetPagination } from '../api';
import type {
User,
UserCreatePayload,
UserFilter,
UserInclude,
UserPage,
UserUpdatePayload,
} from '../domains/user';
import * as z from 'zod';
import { OffsetPaginationSchema } from '../api';
import {
UserCreatePayloadSchema,
UserFilterSchema,
UserIncludeSchema,
UserPageSchema,
UserSchema,
UserUpdatePayloadSchema,
} from '../domains/user';
export const UsersIndexRequestQuerySchema = z.object({
filter: z.union([UserFilterSchema, z.array(UserFilterSchema)]).optional(),
include: UserIncludeSchema.optional(),
page: UserPageSchema.optional(),
});
export const UsersIndexResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
pagination: OffsetPaginationSchema,
users: z.array(UserSchema),
});
export const UsersShowPathParamsSchema = z.object({ id: z.string() });
export const UsersShowRequestQuerySchema = z.object({
include: UserIncludeSchema.optional(),
});
export const UsersShowResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
user: UserSchema,
});
export const UsersCreateRequestQuerySchema = z.object({
include: UserIncludeSchema.optional(),
});
export const UsersCreateRequestBodySchema = z.object({
user: UserCreatePayloadSchema,
});
export const UsersCreateResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
user: UserSchema,
});
export const UsersUpdatePathParamsSchema = z.object({ id: z.string() });
export const UsersUpdateRequestQuerySchema = z.object({
include: UserIncludeSchema.optional(),
});
export const UsersUpdateRequestBodySchema = z.object({
user: UserUpdatePayloadSchema,
});
export const UsersUpdateResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
user: UserSchema,
});
export const UsersDestroyPathParamsSchema = z.object({ id: z.string() });
export const UsersDestroyRequestQuerySchema = z.object({
include: UserIncludeSchema.optional(),
});
export type UsersIndexMethod = 'GET';
export type UsersIndexPath = '/users';
export interface UsersIndexRequestQuery {
filter?: UserFilter | UserFilter[];
include?: UserInclude;
page?: UserPage;
}
export type UsersIndexResponseBody = {
meta?: Record<string, unknown>;
pagination: OffsetPagination;
users: User[];
};
export interface UsersIndexRequest {
query: UsersIndexRequestQuery;
}
export interface UsersIndexResponse {
body: UsersIndexResponseBody;
}
export interface UsersIndex {
method: UsersIndexMethod;
path: UsersIndexPath;
request: UsersIndexRequest;
response: UsersIndexResponse;
}
export type UsersShowMethod = 'GET';
export type UsersShowPath = '/users/:id';
export interface UsersShowPathParams {
id: string;
}
export interface UsersShowRequestQuery {
include?: UserInclude;
}
export type UsersShowResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersShowRequest {
query: UsersShowRequestQuery;
}
export interface UsersShowResponse {
body: UsersShowResponseBody;
}
export interface UsersShow {
method: UsersShowMethod;
path: UsersShowPath;
pathParams: UsersShowPathParams;
request: UsersShowRequest;
response: UsersShowResponse;
}
export type UsersCreateMethod = 'POST';
export type UsersCreatePath = '/users';
export interface UsersCreateRequestQuery {
include?: UserInclude;
}
export interface UsersCreateRequestBody {
user: UserCreatePayload;
}
export type UsersCreateResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersCreateRequest {
body: UsersCreateRequestBody;
query: UsersCreateRequestQuery;
}
export interface UsersCreateResponse {
body: UsersCreateResponseBody;
}
export type UsersCreateErrors = 422;
export interface UsersCreate {
errors: UsersCreateErrors;
method: UsersCreateMethod;
path: UsersCreatePath;
request: UsersCreateRequest;
response: UsersCreateResponse;
}
export type UsersUpdateMethod = 'PATCH';
export type UsersUpdatePath = '/users/:id';
export interface UsersUpdatePathParams {
id: string;
}
export interface UsersUpdateRequestQuery {
include?: UserInclude;
}
export interface UsersUpdateRequestBody {
user: UserUpdatePayload;
}
export type UsersUpdateResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersUpdateRequest {
body: UsersUpdateRequestBody;
query: UsersUpdateRequestQuery;
}
export interface UsersUpdateResponse {
body: UsersUpdateResponseBody;
}
export type UsersUpdateErrors = 422;
export interface UsersUpdate {
errors: UsersUpdateErrors;
method: UsersUpdateMethod;
path: UsersUpdatePath;
pathParams: UsersUpdatePathParams;
request: UsersUpdateRequest;
response: UsersUpdateResponse;
}
export type UsersDestroyMethod = 'DELETE';
export type UsersDestroyPath = '/users/:id';
export interface UsersDestroyPathParams {
id: string;
}
export interface UsersDestroyRequestQuery {
include?: UserInclude;
}
export interface UsersDestroyRequest {
query: UsersDestroyRequestQuery;
}
export interface UsersDestroy {
method: UsersDestroyMethod;
path: UsersDestroyPath;
pathParams: UsersDestroyPathParams;
request: UsersDestroyRequest;
}Sorbus
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 StringFilterSchema = z.object({
contains: z.string().optional(),
endsWith: z.string().optional(),
eq: z.string().optional(),
in: z.array(z.string()).optional(),
startsWith: z.string().optional(),
});
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 StringFilter {
contains?: string;
endsWith?: string;
eq?: string;
in?: string[];
startsWith?: string;
}
export interface Error {
issues: ErrorIssue[];
layer: ErrorLayer;
}import type {
CommentsOperationTree,
PostsOperationTree,
UsersOperationTree,
} from './endpoints';
import { createClientFactory } from 'sorbus';
import { contract } from './contract';
export interface Client {
comments: CommentsOperationTree;
posts: PostsOperationTree;
users: UsersOperationTree;
}
export const createClient = createClientFactory<Client>(contract);import { ErrorSchema } from './api';
import { comments, posts, users } from './endpoints';
export const contract = {
endpoints: {
comments,
posts,
users,
},
error: ErrorSchema,
} as const;import * as z from 'zod';
export const CommentSchema = z.object({
author: z.string(),
body: z.string(),
id: z.string(),
});
export const CommentNestedCreatePayloadSchema = z.object({
author: z.string(),
body: z.string(),
OP: z.literal('create'),
});
export const CommentNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const CommentNestedUpdatePayloadSchema = z.object({
author: z.string().optional(),
body: z.string().optional(),
id: z.string().optional(),
OP: z.literal('update'),
});
export const CommentPageSchema = z.object({
number: z.number().int().min(1).optional(),
size: z.number().int().min(1).max(100).optional(),
});
export const CommentNestedPayloadSchema = z.discriminatedUnion('OP', [
CommentNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
CommentNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
CommentNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface Comment {
author: string;
body: string;
id: string;
}
export interface CommentNestedCreatePayload {
author: string;
body: string;
OP: 'create';
}
export interface CommentNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface CommentNestedUpdatePayload {
author?: string;
body?: string;
id?: string;
OP: 'update';
}
export interface CommentPage {
number?: number;
size?: number;
}
export type CommentNestedPayload =
| (CommentNestedCreatePayload & { OP: 'create' })
| (CommentNestedUpdatePayload & { OP: 'update' })
| (CommentNestedDeletePayload & { OP: 'delete' });export * from './comment';
export * from './post';
export * from './profile';
export * from './user';import type { Comment, CommentNestedPayload } from './comment';
import * as z from 'zod';
import { CommentNestedPayloadSchema, CommentSchema } from './comment';
export const PostNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const PostPageSchema = z.object({
number: z.number().int().min(1).optional(),
size: z.number().int().min(1).max(100).optional(),
});
export const PostSchema = z.object({
comments: z.array(CommentSchema),
id: z.string(),
title: z.string(),
});
export const PostNestedCreatePayloadSchema = z.object({
comments: z.array(CommentNestedPayloadSchema).optional(),
OP: z.literal('create'),
title: z.string(),
});
export const PostNestedUpdatePayloadSchema = z.object({
comments: z.array(CommentNestedPayloadSchema).optional(),
id: z.string().optional(),
OP: z.literal('update'),
title: z.string().optional(),
});
export const PostNestedPayloadSchema = z.discriminatedUnion('OP', [
PostNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
PostNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
PostNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface PostNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface PostPage {
number?: number;
size?: number;
}
export interface Post {
comments: Comment[];
id: string;
title: string;
}
export interface PostNestedCreatePayload {
comments?: CommentNestedPayload[];
OP: 'create';
title: string;
}
export interface PostNestedUpdatePayload {
comments?: CommentNestedPayload[];
id?: string;
OP: 'update';
title?: string;
}
export type PostNestedPayload =
| (PostNestedCreatePayload & { OP: 'create' })
| (PostNestedUpdatePayload & { OP: 'update' })
| (PostNestedDeletePayload & { OP: 'delete' });import type { User } from './user';
import * as z from 'zod';
import { UserSchema } from './user';
export const ProfileSchema: z.ZodType<Profile> = z.lazy(() =>
z.object({
bio: z.string().nullable(),
createdAt: z.iso.datetime(),
id: z.string(),
updatedAt: z.iso.datetime(),
user: UserSchema.optional(),
website: z.string().nullable(),
}),
);
export const ProfileIncludeSchema = z.object({
user: z.boolean().optional(),
});
export const ProfileNestedCreatePayloadSchema = z.object({
bio: z.string().nullable().default(null),
OP: z.literal('create'),
website: z.string().nullable().default(null),
});
export const ProfileNestedDeletePayloadSchema = z.object({
id: z.string(),
OP: z.literal('delete'),
});
export const ProfileNestedUpdatePayloadSchema = z.object({
bio: z.string().nullable().optional(),
id: z.string().optional(),
OP: z.literal('update'),
website: z.string().nullable().optional(),
});
export const ProfileNestedPayloadSchema = z.discriminatedUnion('OP', [
ProfileNestedCreatePayloadSchema.extend({ OP: z.literal('create') }),
ProfileNestedUpdatePayloadSchema.extend({ OP: z.literal('update') }),
ProfileNestedDeletePayloadSchema.extend({ OP: z.literal('delete') }),
]);
export interface Profile {
bio: string | null;
createdAt: string;
id: string;
updatedAt: string;
user?: User;
website: string | null;
}
export interface ProfileInclude {
user?: boolean;
}
export interface ProfileNestedCreatePayload {
bio?: string | null;
OP: 'create';
website?: string | null;
}
export interface ProfileNestedDeletePayload {
id: string;
OP: 'delete';
}
export interface ProfileNestedUpdatePayload {
bio?: string | null;
id?: string;
OP: 'update';
website?: string | null;
}
export type ProfileNestedPayload =
| (ProfileNestedCreatePayload & { OP: 'create' })
| (ProfileNestedUpdatePayload & { OP: 'update' })
| (ProfileNestedDeletePayload & { OP: 'delete' });import type { StringFilter } from '../api';
import type { Post, PostNestedPayload } from './post';
import type { Profile, ProfileInclude, ProfileNestedPayload } from './profile';
import * as z from 'zod';
import { StringFilterSchema } from '../api';
import { PostNestedPayloadSchema, PostSchema } from './post';
import {
ProfileIncludeSchema,
ProfileNestedPayloadSchema,
ProfileSchema,
} from './profile';
export const UserFilterSchema: z.ZodType<UserFilter> = z.lazy(() =>
z.object({
AND: z.array(UserFilterSchema).optional(),
email: z.union([z.string(), StringFilterSchema]).optional(),
NOT: UserFilterSchema.optional(),
OR: z.array(UserFilterSchema).optional(),
username: z.union([z.string(), StringFilterSchema]).optional(),
}),
);
export const UserPageSchema = z.object({
number: z.number().int().min(1).optional(),
size: z.number().int().min(1).max(100).optional(),
});
export const UserIncludeSchema = z.object({
profile: ProfileIncludeSchema.optional(),
});
export const UserSchema = z.object({
createdAt: z.iso.datetime(),
email: z.string(),
id: z.string(),
posts: z.array(PostSchema),
profile: ProfileSchema,
updatedAt: z.iso.datetime(),
username: z.string(),
});
export const UserCreatePayloadSchema = z.object({
email: z.string(),
posts: z.array(PostNestedPayloadSchema).optional(),
profile: ProfileNestedPayloadSchema.optional(),
username: z.string(),
});
export const UserUpdatePayloadSchema = z.object({
email: z.string().optional(),
posts: z.array(PostNestedPayloadSchema).optional(),
profile: ProfileNestedPayloadSchema.optional(),
username: z.string().optional(),
});
export interface UserFilter {
AND?: UserFilter[];
email?: string | StringFilter;
NOT?: UserFilter;
OR?: UserFilter[];
username?: string | StringFilter;
}
export interface UserPage {
number?: number;
size?: number;
}
export interface UserInclude {
profile?: ProfileInclude;
}
export interface User {
createdAt: string;
email: string;
id: string;
posts: Post[];
profile: Profile;
updatedAt: string;
username: string;
}
export interface UserCreatePayload {
email: string;
posts?: PostNestedPayload[];
profile?: ProfileNestedPayload;
username: string;
}
export interface UserUpdatePayload {
email?: string;
posts?: PostNestedPayload[];
profile?: ProfileNestedPayload;
username?: string;
}import type { Operation } from 'sorbus';
import type { OffsetPagination } from '../api';
import type { Comment, CommentPage } from '../domains/comment';
import * as z from 'zod';
import { OffsetPaginationSchema } from '../api';
import { CommentPageSchema, CommentSchema } from '../domains/comment';
export const CommentsIndexRequestQuerySchema = z.object({
page: CommentPageSchema.optional(),
});
export const CommentsIndexResponseBodySchema = z.object({
comments: z.array(CommentSchema),
meta: z.record(z.string(), z.unknown()).optional(),
pagination: OffsetPaginationSchema,
});
export type CommentsIndexMethod = 'GET';
export type CommentsIndexPath = '/comments';
export interface CommentsIndexRequestQuery {
page?: CommentPage;
}
export type CommentsIndexResponseBody = {
comments: Comment[];
meta?: Record<string, unknown>;
pagination: OffsetPagination;
};
export interface CommentsIndexRequest {
query: CommentsIndexRequestQuery;
}
export interface CommentsIndexResponse {
body: CommentsIndexResponseBody;
}
export interface CommentsIndex {
method: CommentsIndexMethod;
path: CommentsIndexPath;
request: CommentsIndexRequest;
response: CommentsIndexResponse;
}
export const comments = {
index: {
method: 'GET',
path: '/comments',
request: {
query: CommentsIndexRequestQuerySchema,
},
response: {
body: CommentsIndexResponseBodySchema,
},
},
} as const;
export interface CommentsOperationTree {
index: Operation<CommentsIndex>;
}export * from './comments';
export * from './posts';
export * from './users';import type { Operation } from 'sorbus';
import type { OffsetPagination } from '../api';
import type { Post, PostPage } from '../domains/post';
import * as z from 'zod';
import { OffsetPaginationSchema } from '../api';
import { PostPageSchema, PostSchema } from '../domains/post';
export const PostsIndexRequestQuerySchema = z.object({
page: PostPageSchema.optional(),
});
export const PostsIndexResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
pagination: OffsetPaginationSchema,
posts: z.array(PostSchema),
});
export type PostsIndexMethod = 'GET';
export type PostsIndexPath = '/posts';
export interface PostsIndexRequestQuery {
page?: PostPage;
}
export type PostsIndexResponseBody = {
meta?: Record<string, unknown>;
pagination: OffsetPagination;
posts: Post[];
};
export interface PostsIndexRequest {
query: PostsIndexRequestQuery;
}
export interface PostsIndexResponse {
body: PostsIndexResponseBody;
}
export interface PostsIndex {
method: PostsIndexMethod;
path: PostsIndexPath;
request: PostsIndexRequest;
response: PostsIndexResponse;
}
export const posts = {
index: {
method: 'GET',
path: '/posts',
request: {
query: PostsIndexRequestQuerySchema,
},
response: {
body: PostsIndexResponseBodySchema,
},
},
} as const;
export interface PostsOperationTree {
index: Operation<PostsIndex>;
}import type { Operation } from 'sorbus';
import type { OffsetPagination } from '../api';
import type {
User,
UserCreatePayload,
UserFilter,
UserInclude,
UserPage,
UserUpdatePayload,
} from '../domains/user';
import * as z from 'zod';
import { OffsetPaginationSchema } from '../api';
import {
UserCreatePayloadSchema,
UserFilterSchema,
UserIncludeSchema,
UserPageSchema,
UserSchema,
UserUpdatePayloadSchema,
} from '../domains/user';
export const UsersIndexRequestQuerySchema = z.object({
filter: z.union([UserFilterSchema, z.array(UserFilterSchema)]).optional(),
include: UserIncludeSchema.optional(),
page: UserPageSchema.optional(),
});
export const UsersIndexResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
pagination: OffsetPaginationSchema,
users: z.array(UserSchema),
});
export const UsersShowPathParamsSchema = z.object({ id: z.string() });
export const UsersShowRequestQuerySchema = z.object({
include: UserIncludeSchema.optional(),
});
export const UsersShowResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
user: UserSchema,
});
export const UsersCreateRequestQuerySchema = z.object({
include: UserIncludeSchema.optional(),
});
export const UsersCreateRequestBodySchema = z.object({
user: UserCreatePayloadSchema,
});
export const UsersCreateResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
user: UserSchema,
});
export const UsersUpdatePathParamsSchema = z.object({ id: z.string() });
export const UsersUpdateRequestQuerySchema = z.object({
include: UserIncludeSchema.optional(),
});
export const UsersUpdateRequestBodySchema = z.object({
user: UserUpdatePayloadSchema,
});
export const UsersUpdateResponseBodySchema = z.object({
meta: z.record(z.string(), z.unknown()).optional(),
user: UserSchema,
});
export const UsersDestroyPathParamsSchema = z.object({ id: z.string() });
export const UsersDestroyRequestQuerySchema = z.object({
include: UserIncludeSchema.optional(),
});
export type UsersIndexMethod = 'GET';
export type UsersIndexPath = '/users';
export interface UsersIndexRequestQuery {
filter?: UserFilter | UserFilter[];
include?: UserInclude;
page?: UserPage;
}
export type UsersIndexResponseBody = {
meta?: Record<string, unknown>;
pagination: OffsetPagination;
users: User[];
};
export interface UsersIndexRequest {
query: UsersIndexRequestQuery;
}
export interface UsersIndexResponse {
body: UsersIndexResponseBody;
}
export interface UsersIndex {
method: UsersIndexMethod;
path: UsersIndexPath;
request: UsersIndexRequest;
response: UsersIndexResponse;
}
export type UsersShowMethod = 'GET';
export type UsersShowPath = '/users/:id';
export interface UsersShowPathParams {
id: string;
}
export interface UsersShowRequestQuery {
include?: UserInclude;
}
export type UsersShowResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersShowRequest {
query: UsersShowRequestQuery;
}
export interface UsersShowResponse {
body: UsersShowResponseBody;
}
export interface UsersShow {
method: UsersShowMethod;
path: UsersShowPath;
pathParams: UsersShowPathParams;
request: UsersShowRequest;
response: UsersShowResponse;
}
export type UsersCreateMethod = 'POST';
export type UsersCreatePath = '/users';
export interface UsersCreateRequestQuery {
include?: UserInclude;
}
export interface UsersCreateRequestBody {
user: UserCreatePayload;
}
export type UsersCreateResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersCreateRequest {
body: UsersCreateRequestBody;
query: UsersCreateRequestQuery;
}
export interface UsersCreateResponse {
body: UsersCreateResponseBody;
}
export type UsersCreateErrors = 422;
export interface UsersCreate {
errors: UsersCreateErrors;
method: UsersCreateMethod;
path: UsersCreatePath;
request: UsersCreateRequest;
response: UsersCreateResponse;
}
export type UsersUpdateMethod = 'PATCH';
export type UsersUpdatePath = '/users/:id';
export interface UsersUpdatePathParams {
id: string;
}
export interface UsersUpdateRequestQuery {
include?: UserInclude;
}
export interface UsersUpdateRequestBody {
user: UserUpdatePayload;
}
export type UsersUpdateResponseBody = {
meta?: Record<string, unknown>;
user: User;
};
export interface UsersUpdateRequest {
body: UsersUpdateRequestBody;
query: UsersUpdateRequestQuery;
}
export interface UsersUpdateResponse {
body: UsersUpdateResponseBody;
}
export type UsersUpdateErrors = 422;
export interface UsersUpdate {
errors: UsersUpdateErrors;
method: UsersUpdateMethod;
path: UsersUpdatePath;
pathParams: UsersUpdatePathParams;
request: UsersUpdateRequest;
response: UsersUpdateResponse;
}
export type UsersDestroyMethod = 'DELETE';
export type UsersDestroyPath = '/users/:id';
export interface UsersDestroyPathParams {
id: string;
}
export interface UsersDestroyRequestQuery {
include?: UserInclude;
}
export interface UsersDestroyRequest {
query: UsersDestroyRequestQuery;
}
export interface UsersDestroy {
method: UsersDestroyMethod;
path: UsersDestroyPath;
pathParams: UsersDestroyPathParams;
request: UsersDestroyRequest;
}
export const users = {
create: {
errors: [422],
method: 'POST',
path: '/users',
request: {
body: UsersCreateRequestBodySchema,
query: UsersCreateRequestQuerySchema,
},
response: {
body: UsersCreateResponseBodySchema,
},
},
destroy: {
method: 'DELETE',
path: '/users/:id',
pathParams: UsersDestroyPathParamsSchema,
request: {
query: UsersDestroyRequestQuerySchema,
},
},
index: {
method: 'GET',
path: '/users',
request: {
query: UsersIndexRequestQuerySchema,
},
response: {
body: UsersIndexResponseBodySchema,
},
},
show: {
method: 'GET',
path: '/users/:id',
pathParams: UsersShowPathParamsSchema,
request: {
query: UsersShowRequestQuerySchema,
},
response: {
body: UsersShowResponseBodySchema,
},
},
update: {
errors: [422],
method: 'PATCH',
path: '/users/:id',
pathParams: UsersUpdatePathParamsSchema,
request: {
body: UsersUpdateRequestBodySchema,
query: UsersUpdateRequestQuerySchema,
},
response: {
body: UsersUpdateResponseBodySchema,
},
},
} as const;
export interface UsersOperationTree {
create: Operation<UsersCreate>;
destroy: Operation<UsersDestroy>;
index: Operation<UsersIndex>;
show: Operation<UsersShow>;
update: Operation<UsersUpdate>;
}