Tutorial 5: Backend Contract Sharing
BasicIn this tutorial, one prompt lets AI show the forward chain of Cabloy’s fullstack contract loop: backend API contracts that generate and refresh the frontend consumption surface.
The teaching thread in this page is the pair of Student actions:
summary/:iddeleteForce/:id
NOTE
This tutorial still runs inside the standalone demo-student sandbox from the earlier pages. Use that sandbox for OpenAPI regeneration experiments so you do not interfere with the repo's real suite-owned a-training/training-student implementation.
Goal
By the end of this tutorial, you will understand:
- how a backend controller and DTO change becomes frontend generated API output
- how backend row-action metadata can drive frontend table actions
- how generated API, thin frontend model helpers, and row-action beans fit into one forward-chain workflow
- why custom resource endpoints that still belong to the same resource should reuse the existing resource-owner instead of creating a competing cache owner
AI Prompt
Give AI a prompt like this:
Please add two custom actions to the Student list:
- Summary: return or display a student summary for the selected row
- Force Delete: permanently delete the selected student through a dedicated row actionWhy this step matters
This is the right step because it reduces duplicated type work across backend and frontend.
Instead of manually synchronizing request and response shapes in two places, this workflow keeps the backend as the source of truth and regenerates the frontend artifacts from that contract.
This step also shows that contract sharing is not only about API methods. It also affects how backend row-action metadata becomes frontend table behavior.
CLI commands to inspect/use
Inspect the relevant command surfaces first:
npm run zova :openapi
npm run zova :openapi:config demo-student
npm run zova :openapi:generate demo-studentIf your workflow also needs refreshed rest-contract output for Cabloy Basic, the related build commands are:
cd zova && npm run build:rest:cabloyBasicAdmin
cd zova && npm run build:rest:cabloyBasicWebUsage notes:
- use the backend controller and DTOs as the starting point
- inspect the module OpenAPI config before generation
- prefer regeneration over hand-written duplicate API layers when the module already owns an OpenAPI contract surface
- keep frontend follow-up thin: treat the module model as a semantic facade over generated API consumers rather than a second contract-definition layer
- if the custom endpoint still belongs to the existing resource, reuse the existing resource-owner for server-state ownership
Generated or affected files
The backend contract anchors are:
vona/src/module/demo-student/src/controller/student.tsvona/src/module/demo-student/src/dto/studentSummary.tsxvona/src/module/demo-student/src/dto/studentSelectResItem.tsx
By the end of this tutorial, your demo-student controller should expose:
@Web.get('summary/:id')
async summary(...) { ... }
@Web.delete('deleteForce/:id')
async deleteForce(...) { ... }The frontend contract and consumption anchors are:
- OpenAPI config:
zova/src/module/demo-student/cli/openapi.config.ts
- generated frontend API:
zova/src/module/demo-student/src/api/demoStudent.ts
- frontend model wrapper:
zova/src/module/demo-student/src/model/student.ts
- custom row-action cells:
zova/src/module/demo-student/src/bean/tableCell.actionSummary.tsxzova/src/module/demo-student/src/bean/tableCell.actionDeleteForce.tsx
After regeneration, src/api/demoStudent.ts should contain generated methods such as:
summary(...)deleteForce(...)
What those files mean in the business thread
This tutorial is easiest to understand as one contract chain:
controller/student.tsdefines the backend action endpointsdto/studentSummary.tsxdefines the response contract for the summary actiondto/studentSelectResItem.tsxdefines the row-action metadata that exposes those actions in the Student list pagecli/openapi.config.tstells the frontend module which backend operations it ownssrc/api/demoStudent.tsis the generated typed API surface created from that backend contractsrc/model/student.tswraps the generated API in a thin frontend semantic facade- the model should reuse the existing resource-owner for server-state ownership when the new API still belongs to the Student resource
tableCell.actionSummary.tsxandtableCell.actionDeleteForce.tsxturn those model methods into visible row actions
That is the practical forward chain: backend controller and DTO truth flows into generated frontend API output, then into thin frontend model helpers, and finally into visible table actions.
Verification
- make sure the local dev workflow is running:
npm run dev- open
http://localhost:7102/admin/ - enter the Student list page
- trigger the Summary row action and verify that it uses the regenerated frontend API and returns the expected Student summary data
- trigger the Force Delete row action and verify that it reaches the custom backend deleteForce contract path
- inspect the source chain and confirm that each layer is present:
controller/student.tsdto/studentSummary.tsxdto/studentSelectResItem.tsxsrc/api/demoStudent.tssrc/model/student.tstableCell.actionSummary.tsxtableCell.actionDeleteForce.tsx
Read more
- Backend Metadata to Frontend Table Actions
- Backend OpenAPI to Frontend SDK
- OpenAPI Guide
- OpenAPI SDK Guide
- SDK Guide
- Server Data
Next step
Continue to Tutorial 6: One Contract Surface, Four Uses.