Rule Cascade
ReferenceExample READMEs

Go example (net/http)

The payments API of backend-spring-boot, on the standard library's net/http with the Go runtime. It enforces payments-transfer.ruleset.yaml from its compiled bundle.

The payments API of backend-spring-boot, on the standard library's net/http with the Go runtime. It enforces payments-transfer.ruleset.yaml (examples/contracts/payments-transfer.ruleset.yaml) from its compiled bundle.

FileWhat it shows
server.goThe four steps on every operation: evaluate, refuse on deny with 422 problem details, persist, run commands once per idempotency key. Read rules that hide fields. The client manifest with an ETag
main.goLoad the bundle once at startup; a bundle that cannot be read stops the process
server_test.goThe behaviour above through real HTTP requests (httptest)

The module has its own go.mod and uses the runtime in this repository through replace <repository>/packages/go => ../../packages/go. It needs Go 1.22 or later (method and wildcard patterns in http.ServeMux).

Run it

From this directory:

go test ./...
go run .            # listens on :8080; RULES_BUNDLE and PORT override the defaults
curl -s localhost:8080/transfers -H 'Content-Type: application/json' -d '{
  "transfer": {"type": "international", "amount": 500, "currency": "USD", "memo": "gift",
               "beneficiary": {"name": "X", "country": "KP", "swiftCode": "ABCDKPPY"}}}'
curl -si localhost:8080/rulesets/acme.payments.transfer/manifest | head -5

Request bodies are read with rulecascade.ParseJSON, which keeps the order of members and the text of every number. The rules read each number as the IEEE 754 double nearest to that text, as every runtime does (specification section 4.2), so an amount is the same number here as in the browser.

The actor comes from the X-Actor-Id and X-Actor-Roles headers to keep the example short. A real service takes it from its authentication layer.

On this page