- Docs
- Tutorials
- Explore the showcase app
Explore the showcase app
Tour examples/showcase, one schema using every DSL feature, served over HTTP and gRPC from one implementation.
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.
cd examples/showcaseSee what one schema can declare
Section titled “See what one schema can declare”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.
Run it
Section titled “Run it”AUTH_JWT_SECRET (32+ bytes) is required by every entrypoint; the app fails closed (Configuration).
export AUTH_JWT_SECRET=dev-only-secret-at-least-32-bytes-long
zever db migrate --adapter=sqlite --dsn=data/showcase.db schema/shop/shop.zengo run ./db/seed # idempotentCheckpoint:
OK applied 16 statement(s) via sqlite{"time":"...","level":"INFO","msg":"seed complete"}Serve and work in two terminals:
go run ./cmd/server # HTTP :8080 + gRPC :9090go run ./cmd/worker # jobs + embedded schedulerCheckpoint, 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:
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:
zever check schema/shop/shop.zenzever fmt schema/shop/shop.zenzever routes schema/shop/shop.zenzever graph schema/shop/shop.zenzever explain ShopService.Checkout schema/shop/shop.zenzever check-boundaries schema/shop/shop.zenExpected 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 CheckoutRegenerate after a schema change
Section titled “Regenerate after a schema change”generated/ is CLI output; never hand-edit it. Run from the repository root so gogen/protogogen import paths resolve:
zever compile examples/showcase/schema/shop/shop.zen \ --backend=atlas,gogen,openapi,proto,protogogen,zenorm \ --out examples/showcase/generatedCheckpoint:
✔ 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.