C validator for Nostr protocol JSON schemas. This is the C equivalent of schemata-validator-rs, built on top of schemata-c.
Validates Nostr events, NIP-11 documents, and protocol messages against the canonical schemata definitions using Draft 7 JSON Schema.
| Project | Language | Role |
|---|---|---|
| nostrability/schemata | JSON/JS | Canonical schema definitions |
| schemata-c | C | Data library (schemas + registry) |
| jsonc-daccord | C | JSON Schema validation engine (nostrability fork) |
| schemata-validator-rs | Rust | Rust equivalent |
JSON Schema validation is not suited for runtime hot paths — it's slow by design due to the breadth of the specification. Use this library in CI and integration tests to catch schema drift at build time, not in production event processing.
Good for:
- CI pipelines that verify your event construction matches the canonical schemas
- Integration tests for clients and relays
- Fuzz testing to discover broken event shapes
Not good for:
- Validating every incoming event at runtime
- Hot paths where latency matters
- Not thread safe. The underlying jsonc-daccord library uses global mutable state. Use process-level parallelism (
fork) if concurrent validation is needed. - No
$refresolution. Acceptable because schemata's compiled schemas are fully inlined (zero$refusage).
The validator depends on three libraries: json-c (system), jsonc-daccord (sibling), and schemata-c (sibling).
Clone all three as siblings:
git clone https://github.com/nostrability/schemata-c.git
git clone https://github.com/nostrability/jsonc-daccord.git
git clone https://github.com/nostrability/schemata-validator-c.gitAdd as a CMake subdirectory:
add_subdirectory(path/to/schemata-validator-c)
target_link_libraries(my_target PRIVATE schemata_validator)#include <schemata/validator.h>
#include <stdio.h>
int main(void) {
const char *event = "{"
"\"id\":\"aabbccdd...\","
"\"pubkey\":\"11223344...\","
"\"created_at\":1700000000,"
"\"kind\":1,"
"\"tags\":[],"
"\"content\":\"hello world\","
"\"sig\":\"aabbccdd...\""
"}";
SchemataValidationResult *r = schemata_validate_note(event);
if (r->valid) {
printf("Valid kind-1 event\n");
} else {
for (size_t i = 0; i < r->error_count; i++) {
printf("Error: %s (at %s)\n",
r->errors[i].message,
r->errors[i].instance_path);
}
}
schemata_result_free(r);
return 0;
}SchemataValidationResult *r = schemata_validate_nip11(
"{\"name\":\"My Relay\",\"supported_nips\":[1,11]}"
);
/* ... check r->valid ... */
schemata_result_free(r);SchemataValidationResult *r = schemata_validate_message(
"[\"NOTICE\",\"rate limited\"]",
SCHEMATA_RELAY,
"Notice"
);
/* ... check r->valid ... */
schemata_result_free(r);| Function | Description |
|---|---|
schemata_validate(schema_json, data_json) |
Validate data against any JSON schema string |
schemata_validate_note(event_json) |
Validate a Nostr event (looks up kind{N}Schema) |
schemata_validate_nip11(doc_json) |
Validate a NIP-11 relay info document |
schemata_validate_message(msg_json, subject, slug) |
Validate a relay/client protocol message |
schemata_get_schema(key) |
Look up a schema by export name (delegates to schemata-c) |
schemata_result_free(result) |
Free a validation result and all its allocated memory |
typedef struct {
bool valid; /* true if no errors */
SchemataValidationError *errors; /* schema violations */
size_t error_count;
SchemataValidationError *warnings; /* additional properties, missing schemas */
size_t warning_count;
} SchemataValidationResult;typedef struct {
const char *instance_path; /* JSON pointer to failing value */
const char *keyword; /* failing JSON Schema keyword */
const char *message; /* human-readable error message */
const char *schema_path; /* JSON pointer into schema */
} SchemataValidationError;Errors are hard schema violations. Warnings flag additional properties not in the schema and unknown kinds/message types.
- Schema pre-processing: strips nested
$idand$schemakeywords that confuse validators errorMessageenrichment: replaces generic validator errors with human-readable messages from schemata'serrorMessageannotations (supports both string and keyword-keyed formats)- Additional properties warnings: detects properties not declared in the schema (allOf-aware) and reports them as warnings
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug
make
ctest -VWith AddressSanitizer:
cmake .. -DCMAKE_BUILD_TYPE=Debug -DSCHEMATA_VALIDATOR_USE_ASAN=ON
make && ctest -VRequires json-c and cmocka (auto-detected via pkg-config).
GPL-3.0-or-later