Network Contracts
Sercrod network directives make the frontend/server contract visible in HTML attributes. This page focuses on the response shapes and trigger timing that must stay aligned with templates.
For directive-level behavior, see Communication.
Trigger Timing
*fetch and *api can run automatically or as user actions depending on the element.
On a non-clickable element, Sercrod treats the directive as initial loading.
<serc-rod data='{"items":[]}' *fetch="/api/items.json" *response="'items'">
<ul>
<li *for="item of items">%item.title%</li>
</ul>
</serc-rod>
On a clickable element, Sercrod treats the directive as an action.
<serc-rod data='{"items":[]}'>
<button type="button" *fetch="/api/items.json" *response="'items'">
Load items
</button>
<ul>
<li *for="item of items">%item.title%</li>
</ul>
</serc-rod>
For *fetch and *api, clickable timing is decided by element tag/type: button, a without download, and button-like input elements. *fetch also treats input[type=image] as clickable. role="button" and tabindex="0" do not change an auto-running element into a click-triggered one.
If the visual design needs a paragraph, list item, or other wrapper, keep the wrapper decorative and place the directive on the actual trigger element:
<p class="load-control">
<button type="button" *fetch="/api/items.json" *response="'items'">
Load items
</button>
</p>
*fetch Destination
*fetch uses *response to place the fetched JSON in host data.
<serc-rod data='{"items":[]}'>
<div *fetch="/api/items.json" *response="'items'"></div>
<ul>
<li *for="item of items">%item.title%</li>
</ul>
</serc-rod>
The response is stored in items. Because the template loops with *for="item of items", items must be an array.
Do not change the server response root without updating the template paths that read it.
*api With *response
*api often uses *response to place the response in a named data key.
<serc-rod data='{"form":{"email":"","message":""},"result":null}'>
<input type="email" *input="form.email">
<textarea *input="form.message"></textarea>
<button
type="button"
*api="/api/contact.php"
method="POST"
body="form"
*response="'result'"
>Send</button>
<p *if="result" *print="result.message"></p>
</serc-rod>
Because the template reads result.message, the endpoint should return:
{
"ok": true,
"message": "Submission received.",
"errors": [],
"received": {
"email": "user@example.com",
"message": "Hello"
}
}
If the endpoint returns { "data": { "message": "..." } }, the template must read result.data.message instead. The template and response shape are a single contract.
Request Body Contract
When body="form" or payload="form" is used, the expression is evaluated in the Sercrod scope and JSON-serialized for non-GET requests.
<button
type="button"
*api="/api/contact.php"
method="POST"
body="form"
*response="'result'"
>Send</button>
For non-GET JSON requests, Sercrod sends a request envelope. The server should read the user payload from the envelope's data field.
Choosing *fetch, *post, And *api
- Use
*fetchfor simple JSON loading. - Use
*postfor sending the current host or staged data as JSON. - Use
*apifor method selection, explicit body expressions, file upload, status fields, and explicit destinations with*response.
For type-then-submit flows, use *lazy on text inputs when parent template refresh may interfere with the user's next click. See Input Timing.