honk#
An ATProto Lexicon validator for Gleam.
What is it?#
honk validates AT Protocol lexicon schemas and data against those schemas. Lexicons are the schema language used by the AT Protocol to define record types, XRPC endpoints, and data structures.
Installation#
gleam add honk@1
Quick Start#
Validate a Lexicon Schema#
import honk
import gleam/json
pub fn main() {
let lexicon = json.object([
#("lexicon", json.int(1)),
#("id", json.string("xyz.statusphere.status")),
#("defs", json.object([
#("main", json.object([
#("type", json.string("record")),
#("key", json.string("tid")),
#("record", json.object([
#("type", json.string("object")),
#("required", json.preprocessed_array([
json.string("status"),
json.string("createdAt"),
])),
#("properties", json.object([
#("status", json.object([
#("type", json.string("string")),
#("minLength", json.int(1)),
#("maxGraphemes", json.int(1)),
#("maxLength", json.int(32)),
])),
#("createdAt", json.object([
#("type", json.string("string")),
#("format", json.string("datetime")),
])),
])),
])),
])),
])),
])
case honk.validate([lexicon]) {
Ok(_) -> io.println("✓ Lexicon is valid")
Error(err) -> io.println("✗ Validation failed: " <> err.message)
}
}
Validate Record Data#
import honk
import gleam/json
pub fn validate_status() {
let lexicons = [my_lexicon] // Your lexicon definitions
let record_data = json.object([
#("status", json.string("👍")),
#("createdAt", json.string("2025-01-15T12:00:00Z")),
])
case honk.validate_record(lexicons, "xyz.statusphere.status", record_data) {
Ok(_) -> io.println("✓ Record is valid")
Error(err) -> io.println("✗ Invalid: " <> err.message)
}
}
Features#
- ✅ 17 Type Validators: string, integer, boolean, bytes, blob, cid-link, null, object, array, union, ref, record, query, procedure, subscription, token, unknown
- ✅ 12 String Format Validators: datetime (RFC3339), uri, at-uri, did, handle, at-identifier, nsid, cid, language, tid, record-key
- ✅ Constraint Validation: length limits, ranges, enums, required fields
- ✅ Reference Resolution: local (
#def), global (nsid#def), and cross-lexicon references - ✅ Circular Dependency Detection: prevents infinite reference loops
- ✅ Detailed Error Messages: validation errors with path information
API Overview#
Main Functions#
validate(lexicons: List(Json))- Validates one or more lexicon schemasvalidate_record(lexicons, nsid, data)- Validates record data against a schemais_valid_nsid(value)- Checks if a string is a valid NSIDvalidate_string_format(value, format)- Validates string against a format
Context Builder Pattern#
import validation/context
import validation/field
let assert Ok(ctx) =
context.builder()
|> context.with_validator(field.dispatch_data_validation)
|> context.with_lexicons([lexicon])
|> context.build
Testing#
gleam test
Implementation#
This implementation aligns with the indigo/atproto/lexicon implementation as much as possible, ensuring compatibility with the ATProto specification and ecosystem.
Documentation#
Further documentation can be found at https://hexdocs.pm/honk.
Development#
gleam run # Run the project
gleam test # Run the tests
gleam build # Build the project
License#
Apache 2.0