Generable & Guide
Overview
The Fm::Generable module and Fm::Guide annotation work together to generate JSON schemas from Crystal structs and add generation constraints, enabling type-safe structured output.
Fm::Generable
Usage
Include Fm::Generable alongside JSON::Serializable in a struct:
struct Character
include JSON::Serializable
include Fm::Generable
getter name : String
getter age : Int32
getter traits : Array(String)
end
This generates a json_schema class method that returns the JSON Schema for the struct:
Character.json_schema
# => {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"integer"},"traits":{"type":"array","items":{"type":"string"}}},"required":["name","age","traits"]}
Type Mapping
Generable maps Crystal types to JSON Schema types:
| Crystal Type | JSON Schema Type |
|---|---|
String |
"string" |
Int8, Int16, Int32, Int64 |
"integer" |
UInt8, UInt16, UInt32, UInt64 |
"integer" |
Float32, Float64 |
"number" |
Bool |
"boolean" |
Array(T) |
"array" with items |
Hash(String, V) |
"object" with additionalProperties |
Enum |
"string" with enum (member names in snake_case) |
Union(A, B, ...) |
oneOf array (non-nil union types) |
Nested Generable type |
"object" with properties |
Nested Types
Types that include Generable are automatically supported as nested objects:
struct Address
include JSON::Serializable
include Fm::Generable
getter street : String
getter city : String
end
struct Person
include JSON::Serializable
include Fm::Generable
getter name : String
getter address : Address
end
Enum Types
Crystal enums are automatically mapped to JSON Schema enum with snake_case member names:
enum Priority
Low
Medium
High
end
struct Task
include JSON::Serializable
include Fm::Generable
getter title : String
getter priority : Priority
end
Task.json_schema
# priority => {"type":"string","enum":["low","medium","high"]}
Hash Types
Hash(String, V) maps to a JSON Schema object with additionalProperties:
struct Config
include JSON::Serializable
include Fm::Generable
getter settings : Hash(String, String)
end
Fm::Guide
The @[Fm::Guide] annotation adds JSON Schema constraints to individual fields, guiding the model's generation.
String Constraints
struct Config
include JSON::Serializable
include Fm::Generable
@[Fm::Guide(description: "Log level setting")]
@[Fm::Guide(any_of: ["debug", "info", "warn", "error"])]
getter log_level : String
@[Fm::Guide(pattern: "^[a-z][a-z0-9_]*$")]
getter identifier : String
@[Fm::Guide(constant: "v1")]
getter version : String
end
Numeric Constraints
struct Range
include JSON::Serializable
include Fm::Generable
@[Fm::Guide(minimum: 0, maximum: 100)]
getter score : Int32
@[Fm::Guide(minimum: 0.0, maximum: 1.0)]
getter confidence : Float64
end
Array Constraints
struct TaggedItem
include JSON::Serializable
include Fm::Generable
@[Fm::Guide(min_items: 1, max_items: 10)]
getter tags : Array(String)
@[Fm::Guide(count: 3)]
getter top_three : Array(String)
end
All Constraint Options
| Option | Type | JSON Schema | Description |
|---|---|---|---|
description |
String |
description |
Human-readable field description |
any_of |
Array |
enum |
Restrict to specific values |
constant |
Any |
const |
Fix to a single value |
minimum |
Number |
minimum |
Minimum numeric value |
maximum |
Number |
maximum |
Maximum numeric value |
pattern |
String |
pattern |
Regex pattern for strings |
min_items |
Int |
minItems |
Minimum array length |
max_items |
Int |
maxItems |
Maximum array length |
count |
Int |
minItems + maxItems |
Exact array length |