An ATProto Lexicon validator for Gleam.
Gleam 100.0%
6 1 4

Clone this repository

https://tangled.org/chadtmiller.com/honk
git@tangled.org:chadtmiller.com/honk

For self-hosted knots, clone URLs may differ based on your setup.

README.md

honk#

Package Version Hex Docs

An AT Protocol Lexicon validator for Gleam.

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#

  • Type Validators: string, integer, boolean, bytes, blob, cid-link, null, object, array, union, ref, record, query, procedure, subscription, token, unknown
  • 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 schemas
  • validate_record(lexicons, nsid, data) - Validates record data against a schema
  • is_valid_nsid(value) - Checks if a string is a valid NSID
  • validate_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