Publish a schema¶
Publishing is the privileged half. It has a separate API and a separate HTTP handler from reading, so that whoever wires authentication cannot give one the other's policy by accident.
In Go¶
reg := schema.New(schema.NewMemoryStore(),
jsonschema.Checker{},
protobuf.Checker{},
)
err := reg.Publish(ctx, schema.Schema{
URN: urn.Schema{Name: "orders.created", Version: 3},
Language: schema.JSONSchema,
Bytes: document,
}, schema.CompatibilityNone)
Over HTTP¶
$ curl -X PUT https://schema.internal.example/publish/schemas/orders.created/3 \
-H 'X-Schema-Language: jsonschema' \
--data-binary @schemas/orders.created.v3.json
For a protobuf descriptor set, add the root message:
$ curl -X PUT https://schema.internal.example/publish/schemas/orders.shipped/1 \
-H 'X-Schema-Language: protobuf' \
-H 'X-Schema-Root: uk.phpboyscout.OrderShipped' \
--data-binary @schemas/orders.shipped.v1.binpb
A descriptor set holds every message the target file depends on and nothing in it says which one a payload is, so the root is required rather than inferred.
The compatibility argument¶
reg.Publish(ctx, s, schema.CompatibilityNone) // accepted
reg.Publish(ctx, s, schema.CompatibilityBackward) // ErrUnsupportedCompatibility
Nothing checks compatibility yet, so asking for a guarantee gets a refusal rather than silence. Over
HTTP that is ?compatibility=backward and a 400.
The argument exists from the first release so that no call site changes signature when a checker arrives. See The compatibility-shaped gap.
Republishing¶
| What you publish | What happens |
|---|---|
| The same identifier, identical bytes | Accepted. A deployment that registers on every start must be idempotent |
| The same identifier, different bytes | ErrImmutable — 409 Conflict over HTTP |
| The same identifier, different language or root | ErrImmutable. Same bytes with a different meaning is still a different schema |
To change a schema, publish the next version. That is what versions are for, and the version is an integer precisely so it claims nothing about compatibility.
The version in the URL must be canonical: /3, never /03 or /+1. Two spellings of one version
would be two identifiers for one schema, and immutability is stated in terms of the identifier.
From CI¶
Publishing from a pipeline is the usual arrangement, and it makes the idempotency above load bearing: a re-run of the same pipeline must be a no-op rather than a conflict.
publish-schemas:
script:
- |
for f in schemas/*.json; do
name=$(basename "$f" .json | cut -d. -f1-2)
version=$(basename "$f" .json | sed 's/.*\.v//')
curl --fail -X PUT "$REGISTRY/publish/schemas/$name/$version" \
-H "X-Schema-Language: jsonschema" \
-H "Authorization: Bearer $REGISTRY_TOKEN" \
--data-binary "@$f"
done
--fail matters. Without it a 409 is a silent success, and the pipeline reports that it published
a schema it did not.