Calling the server: dataRpc and endpoints
An endpoint is a page method the browser calls for a value. This guide shows how a page declares endpoints and how the Source calls them. Fragments of Source built on the server and values loaded when they are read are in Remote content and lazy Data. The Controllers family of the gallery of gramlot-examples has lessons on endpoints, calls on change and calls on click.
dataRpc and endpoints
The page declares an endpoint; a dataRpc in the Source calls it and writes the
answer into Data.
dataRpc(method, result_path=None, timeout=None, **params)
methodis the endpoint name: a method of the page or a path from the page,orders.total(the method name). It can also be a^/=pointer read from Data; read the warning on method names first.result_pathis where the value is written; without it the value is not written. It does not accept?attr.timeoutis in milliseconds; when it expires the call is aborted and fails with an error whosenameisTimeoutError.The other keyword arguments are the endpoint arguments.
^arguments trigger the call,=arguments are only read, as fordataController(Data binding and controllers). The control attributes ofdataControllerapply:_init,_onBuilt,_onStart,_delay,_timing,_userChanges,_if. A false_ifmakes no call;_elsethen runs as inline code.Inline callbacks (inline code):
_onCallingruns before the call with the arguments, and a resultfalsemakes no call;_onResultruns after the value is written, with the arguments plusresult;_onErrorruns on failure, with the arguments pluserror(anRpcErrorwith the outcomecode, the server exception name inremoteNameand itsmessage, a transport error or theTimeoutError). Without_onErrorthe failure is not hidden: it reaches the browser console as an unhandled rejection.The calls of a
dataRpcfollow the request rule: one call in flight, its answer always written; the first trigger during the flight waits with its arguments and is sent when the answer arrives; later triggers do nothing while one waits. Removing the declaration aborts its call.A
dataRpcnested in abuttonruns on click (Buttons and events).
The page declares an endpoint with @endpoint in Python and
Page.registerEndpoint(name) in JavaScript, called after the class. The method
receives the arguments by name (Python) or as one object (JavaScript) and returns
the value: a scalar, a Bag or null. The value is data and never runs code.
dataRpc sends every argument the author writes. Python calls the method with
them as keywords, and a keyword the method does not accept answers
application_error; JavaScript ignores the keys it does not read. A Python endpoint
called from dataRpc therefore declares **kwargs, as the legacy rpc_* methods
do.
from gramlot import Page as BasePage
from gramlot import endpoint
class Page(BasePage):
def main(self, root):
root.input(type="number", value="^.price")
root.dataRpc("with_vat", result_path=".gross", price="^.price",
_onError="console.warn(error.message)")
root.span("^.gross")
@endpoint
def with_vat(self, price, **kwargs):
return round((price or 0) * 1.22, 2)
import {Page as BasePage} from '@gramlot/gramlot/page';
export class Page extends BasePage {
main(root) {
root.input({type: 'number', value: '^.price'});
root.dataRpc({method: 'with_vat', result_path: '.gross', price: '^.price',
_onError: 'console.warn(error.message)'});
root.span('^.gross');
}
with_vat({price}) { return Math.round((price ?? 0) * 122) / 100; }
}
Page.registerEndpoint('with_vat');
@endpoint(auth="rule")andPage.registerEndpoint(name, {auth: 'rule'})protect the endpoint with a rule over tags (|,&,!). A server without theauthcapability knows no identity: every call of a protected endpoint answers the outcomenot_authenticatedand the method does not run.auth="rule"on an element ofmainor of a@sourcefragment protects the element with the same rule. The server drops an element whose rule it refuses, with all its children, when it sends the fragment: the element never reaches the browser, and an accepted element is sent without itsauthattribute. A server without theauthcapability refuses every rule, so the element is never sent. The rule is a string; any other value answersapplication_error. A page built in the browser does not evaluateauth.A declared method name is
[A-Za-z]followed by ASCII letters, digits and_;mainis reserved, and the same method cannot be both an endpoint and a@sourcemethod. A request names it directly or through a path (the method name).An unknown endpoint answers
not_found; an exception raised by the method answersapplication_errorwith itsnameandmessage. Both reach_onError.A string argument that carries a TYTX suffix (
"x::D") is decoded by TYTX, not passed through as text: genro-tytx decodes only text it encoded, so an endpoint does not rely on such strings.The call travels as one envelope on
POST /gramlot/rpc(Server protocol); the page writes nofetch.
From code. gramlot.rpc.call('data', name, params, {signal}) calls an endpoint
and resolves with its value; a failure rejects with the RpcError above. signal
and the disposal of the page abort the call. In a Logic method the page instance
is this.page: await this.page.rpc.call('data', 'with_vat', {price: 10}).
gramlot.rpc.callSync('data', name, params) waits for the answer and returns the
value, as the legacy genro.serverCall without callback. It blocks the page until
the answer arrives, and only a transport with synchronous calls sends it (HTTP);
on any other, such as the serverless Worker, it throws. Browsers deprecate the
synchronous request on the main thread. The arguments of both are data: live Source
nodes and DOM elements are refused.