Hash Responses
Expose plain hashes instead of ActiveRecord models
API Definition
config/apis/lazy_cow.rb
rb
# frozen_string_literal: true
Apiwork::API.define '/lazy_cow' do
key_format :camel
export :openapi
export :typescript
export :zod
resource :status, only: [] do
collection do
get :health
get :stats
end
end
endContracts
app/contracts/lazy_cow/status_contract.rb
rb
# frozen_string_literal: true
module LazyCow
class StatusContract < Apiwork::Contract::Base
action :health do
response do
body do
string :status
datetime :timestamp
string :version
end
end
end
action :stats do
response do
body do
integer :users_count
integer :posts_count
integer :uptime_seconds
end
end
end
end
endControllers
app/controllers/lazy_cow/statuses_controller.rb
rb
# frozen_string_literal: true
module LazyCow
class StatusesController < ApplicationController
def health
expose(
{
status: 'ok',
timestamp: Time.current,
version: '1.0.0',
},
)
end
def stats
expose(
{
posts_count: 5678,
uptime_seconds: 86_400,
users_count: 1234,
},
)
end
end
endRequest Examples
Health check
Request
http
GET /lazy_cow/status/healthResponse 200
json
{
"status": "ok",
"timestamp": "2024-01-01T12:00:00.000Z",
"version": "1.0.0"
}System statistics
Request
http
GET /lazy_cow/status/statsResponse 200
json
{
"postsCount": 5678,
"uptimeSeconds": 86400,
"usersCount": 1234
}Generated Output
Introspection
json
{
"base_path": "/lazy_cow",
"enums": {
"layer": {
"deprecated": false,
"description": null,
"example": null,
"values": [
"http",
"contract",
"domain"
]
}
},
"error_codes": {},
"info": null,
"resources": {
"status": {
"actions": {
"health": {
"deprecated": false,
"description": null,
"method": "get",
"operation_id": null,
"path": "/status/health",
"raises": [],
"request": {
"body": {},
"query": {}
},
"response": {
"body": {
"default": null,
"deprecated": null,
"description": null,
"example": null,
"nullable": null,
"optional": null,
"type": "object",
"partial": null,
"shape": {
"status": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "string",
"format": null,
"max": null,
"min": null
},
"timestamp": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "datetime"
},
"version": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "string",
"format": null,
"max": null,
"min": null
}
}
},
"no_content": false
},
"summary": null,
"tags": []
},
"stats": {
"deprecated": false,
"description": null,
"method": "get",
"operation_id": null,
"path": "/status/stats",
"raises": [],
"request": {
"body": {},
"query": {}
},
"response": {
"body": {
"default": null,
"deprecated": null,
"description": null,
"example": null,
"nullable": null,
"optional": null,
"type": "object",
"partial": null,
"shape": {
"posts_count": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "integer",
"format": null,
"max": null,
"min": null
},
"uptime_seconds": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "integer",
"format": null,
"max": null,
"min": null
},
"users_count": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "integer",
"format": null,
"max": null,
"min": null
}
}
},
"no_content": false
},
"summary": null,
"tags": []
}
},
"identifier": "status",
"parent_identifiers": [],
"path": "status",
"resources": {}
}
},
"types": {
"error": {
"deprecated": false,
"description": null,
"discriminator": null,
"example": null,
"extends": [],
"shape": {
"issues": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "array",
"max": null,
"min": null,
"of": {
"default": null,
"deprecated": null,
"description": null,
"example": null,
"nullable": null,
"optional": null,
"type": "reference",
"reference": "issue"
},
"shape": {}
},
"layer": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "reference",
"reference": "layer"
}
},
"type": "object",
"variants": []
},
"error_response_body": {
"deprecated": false,
"description": null,
"discriminator": null,
"example": null,
"extends": [
"error"
],
"shape": {},
"type": "object",
"variants": []
},
"issue": {
"deprecated": false,
"description": null,
"discriminator": null,
"example": null,
"extends": [],
"shape": {
"code": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "string",
"format": null,
"max": null,
"min": null
},
"detail": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "string",
"format": null,
"max": null,
"min": null
},
"meta": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "object",
"partial": false,
"shape": {}
},
"path": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "array",
"max": null,
"min": null,
"of": {
"default": null,
"deprecated": null,
"description": null,
"example": null,
"nullable": null,
"optional": null,
"type": "string",
"format": null,
"max": null,
"min": null
},
"shape": {}
},
"pointer": {
"default": null,
"deprecated": false,
"description": null,
"example": null,
"nullable": false,
"optional": false,
"type": "string",
"format": null,
"max": null,
"min": null
}
},
"type": "object",
"variants": []
}
}
}TypeScript
ts
export interface StatusHealthResponse {
body: StatusHealthResponseBody;
}
export type StatusHealthResponseBody = { status: string; timestamp: string; version: string };
export interface StatusStatsResponse {
body: StatusStatsResponseBody;
}
export type StatusStatsResponseBody = { postsCount: number; uptimeSeconds: number; usersCount: number };Zod
ts
import { z } from 'zod';
export const StatusHealthResponseBodySchema = z.object({ status: z.string(), timestamp: z.iso.datetime(), version: z.string() });
export const StatusHealthResponseSchema = z.object({
body: StatusHealthResponseBodySchema
});
export const StatusStatsResponseBodySchema = z.object({ postsCount: z.number().int(), uptimeSeconds: z.number().int(), usersCount: z.number().int() });
export const StatusStatsResponseSchema = z.object({
body: StatusStatsResponseBodySchema
});
export interface StatusHealthResponse {
body: StatusHealthResponseBody;
}
export type StatusHealthResponseBody = { status: string; timestamp: string; version: string };
export interface StatusStatsResponse {
body: StatusStatsResponseBody;
}
export type StatusStatsResponseBody = { postsCount: number; uptimeSeconds: number; usersCount: number };OpenAPI
yml
---
openapi: 3.1.0
info:
title: "/lazy_cow"
version: 1.0.0
paths:
"/status/health":
get:
operationId: statusHealth
responses:
'200':
content:
application/json:
schema:
properties:
status:
type: string
timestamp:
type: string
format: date-time
version:
type: string
type: object
required:
- status
- timestamp
- version
description: Successful response
"/status/stats":
get:
operationId: statusStats
responses:
'200':
content:
application/json:
schema:
properties:
postsCount:
type: integer
uptimeSeconds:
type: integer
usersCount:
type: integer
type: object
required:
- postsCount
- uptimeSeconds
- usersCount
description: Successful response
components:
schemas: {}