Event catalogue
Schema registry with versioning, validation, and governance for message payloads
The event catalogue is a centralized registry of event types and their schemas. It defines the structure of messages flowing through your channels, validates payloads at publish time, and tracks schema evolution over time.
What the event catalogue provides
| Capability | Description |
|---|---|
| Schema registration | Define the expected structure of message payloads using JSON Schema |
| Versioning | Track schema changes with semantic versioning |
| Validation | Reject messages that do not conform to the registered schema |
| Discovery | Browse available event types and their documentation |
| Governance | Control who can publish specific event types |
Registering an event type
Define an event type with a name, version, and JSON Schema describing the payload.
await npayload.eventCatalogue.register({
name: 'order.created',
version: '1.0.0',
description: 'Published when a new order is placed',
schema: {
type: 'object',
required: ['orderId', 'customerId', 'items', 'total'],
properties: {
orderId: { type: 'string' },
customerId: { type: 'string' },
items: {
type: 'array',
items: {
type: 'object',
required: ['sku', 'quantity', 'price'],
properties: {
sku: { type: 'string' },
quantity: { type: 'integer', minimum: 1 },
price: { type: 'number', minimum: 0 },
},
},
},
total: { type: 'number', minimum: 0 },
},
},
});Schema versioning
Event types follow semantic versioning (semver). When you update a schema, you publish a new version.
| Version bump | When to use | Example |
|---|---|---|
| Patch (1.0.0 to 1.0.1) | Documentation changes, no structural changes | Updated field descriptions |
| Minor (1.0.0 to 1.1.0) | New optional fields added | Added optional couponCode field |
| Major (1.0.0 to 2.0.0) | Breaking changes (removed or renamed fields) | Renamed customerId to buyerId |
// Register a new version with an additional optional field
await npayload.eventCatalogue.register({
name: 'order.created',
version: '1.1.0',
description: 'Published when a new order is placed',
schema: {
type: 'object',
required: ['orderId', 'customerId', 'items', 'total'],
properties: {
orderId: { type: 'string' },
customerId: { type: 'string' },
items: { type: 'array', items: { type: 'object' } },
total: { type: 'number', minimum: 0 },
couponCode: { type: 'string' }, // New optional field
},
},
});Payload validation
When a channel is linked to an event type, npayload validates every published message against the registered schema. Invalid messages are rejected before delivery.
// Link a channel to an event type
await npayload.channels.create({
name: 'orders',
eventType: 'order.created',
eventVersion: '1.x', // Accept any 1.x version
});
// This succeeds (valid payload)
await npayload.messages.publish({
channel: 'orders',
payload: {
orderId: 'ord_123',
customerId: 'cust_456',
items: [{ sku: 'WIDGET-001', quantity: 2, price: 29.99 }],
total: 59.98,
},
});
// This is rejected (missing required field 'total')
await npayload.messages.publish({
channel: 'orders',
payload: {
orderId: 'ord_124',
customerId: 'cust_789',
items: [{ sku: 'WIDGET-002', quantity: 1, price: 15.00 }],
// Missing 'total' field
},
});
// Throws: ValidationError: payload.total is requiredSchema validation happens before fan-out. Invalid messages never reach subscribers, reducing noise and preventing downstream errors.
Schema evolution rules
npayload enforces compatibility rules to prevent breaking changes from affecting existing consumers.
| Rule | Description |
|---|---|
| Backward compatible | New schema can read data written by the old schema |
| Forward compatible | Old schema can read data written by the new schema |
| Full compatible | Both backward and forward compatible |
Major version bumps (breaking changes) require all active subscribers to acknowledge the new schema before it becomes the default. This prevents silent breakage.
Discovering event types
Browse the catalogue to find available event types, their schemas, and which channels use them.
// List all registered event types
const types = await npayload.eventCatalogue.list();
// Get details for a specific event type
const orderCreated = await npayload.eventCatalogue.get('order.created');
console.log(orderCreated.name); // 'order.created'
console.log(orderCreated.versions); // ['1.0.0', '1.1.0']
console.log(orderCreated.channels); // ['orders']
console.log(orderCreated.schema); // JSON Schema object
// List versions for an event type
const versions = await npayload.eventCatalogue.listVersions('order.created');Governance
Control which applications and services can publish specific event types. This prevents unauthorized services from publishing events they do not own.
// Restrict who can publish an event type
await npayload.eventCatalogue.setOwnership({
eventType: 'order.created',
allowedPublishers: ['order-service', 'checkout-service'],
});Use cases
| Use case | How the event catalogue helps |
|---|---|
| API contracts | Define the expected payload structure between services |
| Documentation | Self-documenting event types with schemas and descriptions |
| Type generation | Generate TypeScript types from registered schemas |
| Data quality | Reject malformed messages at the source |
| Compliance | Audit trail of schema changes and who made them |
Next steps
- Messages to understand how payloads are published and validated
- Channels to learn how channels link to event types
- Marketplace to discover and share event types across organisations
Was this page helpful?