Getting started¶
By the end of this you will have validated a message against an embedded schema, seen a non-conforming payload rejected, and seen an unresolvable one pass with a counter incremented. No registry is running at any point, which is the design rather than a shortcut.
1. Install¶
2. Embed a schema¶
package orders
import (
_ "embed"
"gitlab.com/phpboyscout/go/cloudevents/urn"
"gitlab.com/phpboyscout/go/schema"
"gitlab.com/phpboyscout/go/schema/jsonschema"
)
//go:embed schemas/orders.created.v3.json
var ordersCreated []byte
func registry() (*schema.Registry, error) {
return schema.Embed(schema.Schema{
URN: urn.Schema{Name: "orders.created", Version: 3},
Language: schema.JSONSchema,
Bytes: ordersCreated,
})
}
Embed registers a no-op checker for each language it sees, so you do not have to know which
checkers to wire.
3. Build a guard¶
reg, err := registry()
if err != nil {
return err
}
guard := schema.NewGuard(reg, []schema.Validator{jsonschema.New()})
The validator lives in its own package so that a service validating JSON does not carry a protobuf runtime, and vice versa. The registry itself needs neither: to a store, a schema is bytes.
4. Validate¶
err = guard.Validate(ctx, "urn:phpboyscout:schema:orders.created:3", []byte(`{"order":"4172"}`))
// nil
err = guard.Validate(ctx, "urn:phpboyscout:schema:orders.created:3", []byte(`{}`))
// errors.Is(err, schema.ErrInvalidPayload) — the schema resolved, and this does not match
5. See it fail open¶
Ask for a version nothing holds:
err = guard.Validate(ctx, "urn:phpboyscout:schema:orders.created:9", []byte(`{}`))
// nil — the message goes through
guard.Unvalidated()
// 1
That is the asymmetry the whole module is built around. Could not resolve fails open and is counted; resolved and did not match fails closed. Read Why it fails open for the reasoning, and Alert on unvalidated messages for what to do with the counter.
6. Wire it into a CloudEvents handler¶
e, err := cloudevents.Unmarshal(msg.Header, msg.Data)
if err != nil {
logger.Error("refused a CloudEvent", "id", e.ID, "err", err)
return
}
if err := guard.Validate(ctx, e.DataSchema, e.Data); err != nil {
logger.Error("payload does not match its schema", "id", e.ID, "schema", e.DataSchema, "err", err)
return
}
handle(e)
Where next¶
- Publish a schema — the privileged half.
- Run the registry — when a service meets a URN it does not hold.
- Why a published URN cannot change.