Data Interface
Use LyteNyte Grid's server data loading APIs to fetch and render row data from your backend.
LyteNyte Grid sends requests to the server using a defined request structure and expects responses in a specific format. This request/response cycle is the server data interface, i.e. the protocol LyteNyte Grid uses to exchange data.
Note
This section introduces the server data interface types and gives an overview. For a practical guide, see the Server Row Data guide.
Request Interface
The server data interface centers on the request interface. See the API reference for
the full specification. The TypeScript definition of the
DataRequest interface is shown below:
export interface DataRequest { readonly id: string; readonly path: (string | null)[]; readonly start: number; readonly end: number; readonly rowStartIndex: number; readonly rowEndIndex: number;}Here is an example request:
{ id: "__root__:0-100", path: [], start: 0, end: 100, rowStartIndex: 0, rowEndIndex: 100}The request id is "__root__:0-100”. LyteNyte Grid generates a unique
id for each request but doesn’t guarantee the id format, so
don’t use it in application logic. When two requests share the
same id, they target the same rows, and their responses populate
the same row range. This behavior is useful for deduplicating requests.
The path, start, and end properties determine the specific
row slice a request targets. The server data source divides the view
into row slices. Each slice is relative to the view root
or a group row node. An empty path targets the root.
Info
The server data source represents rows as a tree. LyteNyte Grid flattens the tree and renders rows according to the current scroll position. In this documentation, the term “view” refers to the rows currently displayed.
The rowStartIndex and rowEndIndex project the placement of returned rows
in the grid view, rather than acting as strict constraints. You can safely
ignore these properties unless your server keeps the entire expanded
and grouped table in memory.
When you use row groups, the requested slice can target a group expansion
to fetch that group’s child nodes. For a grid grouped by "Group A"
and "Group B", the data request is as follows:
// For a data slice that is an expansion of just Group A{ id: "__root__:0-100", path: ["Alpha"], start: 0, end: 100, rowStartIndex: 0, rowEndIndex: 100}
// For a data slice that is an expansion of Group A followed by and expansion for a child node for Group B{ id: "__root__:0-100", path: ["Alpha", "Beta"], start: 0, end: 100, rowStartIndex: 0, rowEndIndex: 100}Consider the first request object, which has path: ["Alpha"]. The server should treat
this as: “Fetch rows where Group A = “Alpha”.” LyteNyte Grid then groups the
returned rows by Group B.
The second request object, with path: ["Alpha", "Beta"], targets leaf rows.
In this case, Group A = “Alpha” and Group B = “Beta”.
This example shows how path defines the data slice the server
should return. LyteNyte Grid combines these slices to build a coherent view.
Response Interface
The server receives data requests and returns responses. The response types are defined below. A single request can produce multiple responses, and LyteNyte Grid’s server data source supports this behavior.
There are two distinct response types:
- Scrollable Rows: Detailed in Scrollable Rows API reference.
- Pinned Rows (Top or Bottom): Detailed in the Pinned Rows API Reference.
LyteNyte Grid expects an array of responses. This allows the server to batch multiple response types into a single network payload.
Data Response for Scrollable Rows
The DataResponse interface defines the data response for scrollable
rows. The TypeScript definition is as follows:
export interface DataResponse { readonly kind: "center"; readonly data: (DataResponseLeafItem | DataResponseBranchItem)[]; readonly size: number; readonly asOfTime: number; readonly path: (string | null)[]; readonly start: number; readonly end: number;}The response interface mirrors several request fields and adds additional fields. An example response looks like:
{ kind: "center", data: [ { kind: "leaf", id: "1", data: [1,2,3] }, // More rows as ], size: 230_000, asOfTime: 1759391811069, // Some Unix Timestamp path: [], start: 0, end: 100}The scrollable row DataResponse object contains the following properties:
kind: Must be"center"to distinguish scrollable rows from pinned rows.data: The row data returned by the server, containing leaf or branch data items.size: Defines the relative row count for the responsepath. An emptypathindicates the root row count. Row counts are relative to theirpathbecause grouping creates branches in the row tree. LyteNyte Grid flattens the tree to produce the rendered rows, and the final count reflects expanded and collapsed groups.asOfTime: A Unix timestamp. It resolves collisions when multiple responses map to the same row. The response with the laterasOfTimetakes precedence. Conflicts can occur because requests are asynchronous and responses may arrive out of order.path,start,end: Mirror theDataRequestproperties. Avoid modifying these values in the response.
Leaf Row Data
Leaf row data uses the DataResponseLeafItem type. Its TypeScript definition is
shown below:
export interface DataResponseLeafItem { readonly kind: "leaf"; readonly id: string; readonly data: any;}Like DataResponse, DataResponseLeafItem includes a kind property.
The kind value must be "leaf". LyteNyte Grid uses this value
to determine whether the response data creates a leaf row node.
Each DataResponseLeafItem creates one row node, and the item’s id maps
directly to the row node’s id, associating the payload’s data with that specific row node.
Branch Row Data
Branch row data is represented by DataResponseBranchItem. LyteNyte Grid uses these items to
create row group nodes. Row group nodes represent branches in the view that may be expanded or collapsed.
The TypeScript interface for DataResponseBranchItem is shown below.
export interface DataResponseBranchItem { readonly kind: "branch"; readonly id: string; readonly data: any; readonly key: string | null; readonly childCount: number;}The DataResponseBranchItem includes the following properties for group nodes:
kind: Must be"branch"to create a group node.id: Maps to the group node’sid.data: Set on the group node; it typically contains the group’s aggregated data.key: Attached to the group node and used to position it within the server data source’s row tree.childCount: Required. Indicates the number of child nodes in the group.
The close mapping between DataResponseBranchItem and the row group node
is intentional. LyteNyte Grid maps the server response directly to node creation to improve performance.
Data Response For Pinned Rows
Pinned rows are always visible in the view, so LyteNyte Grid cannot detect changes to them. To address this, the server data source allows developers to push pinned row responses alongside scrollable row responses.
The DataResponsePinned interface defines the response type that
LyteNyte Grid expects:
export interface DataResponsePinned { readonly kind: "top" | "bottom"; readonly data: DataResponseLeafItem[]; readonly asOfTime: number;}The pinned response type is simpler than DataResponse because pinned rows are always leaf rows.
The kind property must be either "top" or "bottom", and tells LyteNyte Grid where to
create the pinned row nodes. Like DataResponse, the data property contains the row data, and
the asOfTime property resolves conflicts when writing rows to memory.
Query Fetcher Function
The LyteNyte Grid server data source requires a queryFn as the primary
data-loading handler. The server data source calls queryFn whenever the
view changes and passes the requests for the new view.
The function is responsible for fetching responses from the server, either with an HTTP request or a WebSocket message, and returning the data. A brief code example is shown below:
const ds = useServerDataSource<MyDataType>({ queryFn: (params) => { return Server(params.requests); }, queryKey: [], // Required});The queryFn function receives a params object, which includes the data requests for
the current grid view. This object is described by the QueryFnParams type whose TypeScript definition is
shown below:
export interface QueryFnParams<K extends unknown[]> { readonly queryKey: K; readonly requests: DataRequest[]; readonly reqTime: number; readonly model: { readonly rowGroupExpansions: Record<string, boolean | undefined>; };}The queryFn returns a Promise of type (DataResponse | DataResponsePinned)[]. This
array-based design lets LyteNyte Grid request data in slices, giving the queryFn
implementation flexibility to optimize how it fetches data and returns responses.
The requests property contains the data requests for the current view. It is always an array, not a
single item. Each request should have at least one matching response, but the server may return
additional responses to preload data.
The reqTime property is a Unix timestamp of when the request was made. The server may use it to set
the asOfTime, or ignore it if responses define their own freshness rules.
The model property describes the grid’s view configuration. This contains the current rowGroupExpansions
state. You can use this value to determine if a group is expanded or collapsed when there are row groups
applied to the grid.
Next Steps
- Server Row Data: Slice and load rows from the server.
- Server Row Sorting: Sort rows on the server using a defined sort model.
- Server Row Filtering: Filter server-side rows using the server data source.
- Optimistic Loading: Pre-fetch data using optimistic loading to reduce perceived latency.
