Skip to content
Zever
Home

Explore the showcase app

Tour examples/showcase, one schema using every DSL feature, served over HTTP and gRPC from one implementation.

2 min readEdit on GitHub

You will run examples/showcase: one schema using every DSL feature, served over HTTP and gRPC from one implementation. It takes about 15 minutes. You need Go 1.27+, the zever CLI, and a repo clone. For a narrow flow, see Build a booking API.

All commands run from examples/showcase/ unless noted.

Terminal window
cd examples/showcase

schema/shop/shop.zen is the whole domain (User, Profile, Category, Product, Tag, Order, OrderItem, Review, plus ShopService). When you wonder whether the DSL supports a shape, grep this schema first. See Zen syntax for each feature alone.

Feature Where
All 11 scalars User fields
Named enum OrderStatus, Role
Inline enum() Order.priority
Optional field and @default User.nickname, Order.note
has_many / belongs_to the User/Order/OrderItem/Review graph
has_one (@unique foreign key) User.profile
many_to_many + reciprocal join_table Product.tags
index() and @unique index Product, Order
@schema Order to a separate billing schema
@renamed_from Product.headline (was title)
message request, nested, and returns CreateOrderRequest, CheckoutRequest, OrderReceipt
Every HTTP verb, auth: shape, permission: check, errors:, paginated: true ShopService RPCs
Job params, queues, retry shapes, cron and dispatch 4 jobs, 2 schedules

Understand one implementation, two transports

Section titled “Understand one implementation, two transports”

cmd/server mirrors zever generate server: HTTP (:8080) and gRPC (:9090) from one container, with auth enforced identically on both through the same generated GRPCPolicies plus authz. The logic lives once, in internal/service/shop/shop_service.go (ShopServiceImpl, 9 RPCs); the /api/* routes that need richer shapes are thin adapters over it, never a second copy. cmd/worker mirrors zever generate worker: one handler per job, one registration per schedule.

AUTH_JWT_SECRET (32+ bytes) is required by every entrypoint; the app fails closed (Configuration).

Terminal window
export AUTH_JWT_SECRET=dev-only-secret-at-least-32-bytes-long
zever db migrate --adapter=sqlite --dsn=data/showcase.db schema/shop/shop.zen
go run ./db/seed # idempotent

Checkpoint:

OK applied 16 statement(s) via sqlite
{"time":"...","level":"INFO","msg":"seed complete"}

Serve and work in two terminals:

Terminal window
go run ./cmd/server # HTTP :8080 + gRPC :9090
go run ./cmd/worker # jobs + embedded scheduler

Checkpoint, server then worker:

{"time":"...","level":"INFO","msg":"http server listening","addr":":8080"}
{"time":"...","level":"INFO","msg":"grpc server listening","addr":":9090"}
{"time":"...","level":"INFO","msg":"worker started","jobs":4,"schedules":2}

Prove HTTP parity with curl. Every /api/* route except register and login needs a bearer token:

Terminal window
curl -s -X POST localhost:8080/api/register -H 'Content-Type: application/json' \
-d '{"email":"you@example.com","name":"You","password":"correct horse battery staple"}'
TOKEN=$(curl -s -X POST localhost:8080/api/login -H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"correct horse battery staple"}' | jq -r .token)
curl -s localhost:8080/api/products -H "Authorization: Bearer $TOKEN" | head -c 200
[{"id":"seed-product-gizmo","category_id":"seed-category-gadgets","sku":"GIZMO-002",...}]

An unauthenticated call to a guarded RPC fails identically on :8080 (401 missing bearer token) and :9090.

Inspect the schema without running anything

Section titled “Inspect the schema without running anything”

Every command here is read-only:

Terminal window
zever check schema/shop/shop.zen
zever fmt schema/shop/shop.zen
zever routes schema/shop/shop.zen
zever graph schema/shop/shop.zen
zever explain ShopService.Checkout schema/shop/shop.zen
zever check-boundaries schema/shop/shop.zen

Expected output shape:

# check: OK 1 file(s) valid
# fmt: no output when already formatted (lists files that would change; --write rewrites)
# routes: GET /products -> shop.ShopService.ListProducts, one line per RPC
# graph: Mermaid entity nodes with relation edges
# explain: transports, auth, permission, and error set for Checkout

generated/ is CLI output; never hand-edit it. Run from the repository root so gogen/protogogen import paths resolve:

Terminal window
zever compile examples/showcase/schema/shop/shop.zen \
--backend=atlas,gogen,openapi,proto,protogogen,zenorm \
--out examples/showcase/generated

Checkpoint:

✔ compiled 1 file(s) → examples/showcase/generated (14 outputs, backends: atlas,gogen,openapi,proto,protogogen,zenorm)

Everything under internal/app, internal/service, internal/api, the schema, .env, wiring.go, and the tests is hand-owned and never overwritten.

Troubleshooting

The server exits naming AUTH_JWT_SECRET. Same fail-closed gate as bookings. Export a 32+ byte dev value in every terminal running an entrypoint.

zever compile writes to the wrong import paths. You ran it from examples/showcase/. Re-run from the repo root.

HTTP works but gRPC auth behaves differently. That is a parity-test failure, not a config difference: both transports share GRPCPolicies plus authz. Run the cross-transport tests and fix the implementation, not the transport wiring.