Data Interface
Use LyteNyte Grid's server data loading interfaces to load and display server-provided row data efficiently.
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.
This section introduces the server data interface types and provides a high-level overview. For a practical guide, see the Server Row Data guide.
The Request Interface
At the core of the server data interface is the request interface, the API description of which
may be found in the API reference. In plain
typescript the DataRequest
interface is relatively simple:
export interface DataRequest {readonly id: string;readonly path: (string | null)[];readonly start: number;readonly end: number;readonly rowStartIndex: number;readonly rowEndIndex: number;}
An example of the request may look something like:
{id: "__root__:0-100",path: [],start: 0,end: 100,rowStartIndex: 0,rowEndIndex: 100}
The request has an id
of "__root__:0-100"
. Unique id
s are created for each request by
LyteNyte Grid. LyteNyte Grid makes no guarantees about the construction of the id
, so do not rely
on its form for logic in your applications. If two requests share the same id
, the requests are
equal from a data-fetching standpoint. In other words, their responses write data for the same rows.
This behavior is useful for deduping requests.
The path
, start
, and end
properties determine which slice of the view the request targets. The
server data source divides the view into slices of rows. Each slice is relative to the root of the
view or to a group row node (in the case of row groups). An empty path
value indicates that the
slice requested is for the root. In this example, the data request is for the first 100 rows at the
root of the view.
LyteNyte Grid represents rows as a tree when using the server data source. The tree is flattened, and rows are displayed based on the grid's current scroll position. When these docs refer to the view, they specifically mean the rows that LyteNyte Grid displays to the user.
The rowStartIndex
and rowEndIndex
provide a projected placement of the returned rows in the
grid's view. These indices are not strict constraints. They are useful in advanced cases where the
server holds the full table in memory (with expansions and groupings). Since this is rarely the case,
most servers ignore these properties. They are included for completeness; developers should not
worry if rowStartIndex
or rowEndIndex
go unused.
When row groups exist, the requested slice may target a group expansion, that is, the child nodes of
a group. For example, consider a grid grouped by two columns: "Group A"
and "Group B"
.
A data request in this scenario may look like the following:
// 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}
Take the first request object, which has a path of ["Alpha"]
. The server should interpret this
as: "fetch the rows where Group A
has the value "Alpha"
." These rows are then grouped by
Group B
, with the first group value equal to "Alpha"
.
The second request object, with path ["Alpha", "Beta"]
, targets the leaf rows. Here, Group A
is "Alpha"
and Group B
is "Beta"
.
This illustrates how the path
property defines the slice of data the server should return.
LyteNyte Grid stitches these response slices together to form a coherent view for users.
Response Interface
The server receives data requests and must know how to respond. The types of responses a server can send are described in this section. A single data request may result in one or more data responses, which is valid and expected by LyteNyte Grid's server data source.
There are two distinct response types:
- A data response for scrollable rows, described in this API reference.
- A data response for pinned rows (top or bottom), described in this API reference.
LyteNyte Grid expects an array of responses, so the server may send multiple response types in the same network round trip.
Data Response for Scrollable Rows
The data response for scrollable rows uses the DataResponse
interface. Its TypeScript definition is
shown below:
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 includes additional fields compared to the request interface, while some fields mirror those in the request. An example response is shown below:
{kind: "center",data: [{ kind: "leaf", id: "1", data: [1,2,3] },// More rows as],size: 230_000,asOfTime: 1759391811069, // Some Unix Timestamppath: [],start: 0,end: 100}
The kind
property of the DataResponse
object should always be "center"
. LyteNyte Grid uses
this value to determine whether a response is for scrollable or pinned rows.
The data
property contains the row data returned by the server. Row data may be either a leaf data
item or a branch data item. These are explained below.
The size
property sets the relative row count for the response path. An empty path
value indicates
the root row count. Row counts are relative to their path because row groupings create branches in
the row tree. The tree is then flattened to produce the displayed rows. The final row count is the
flattened view's row count, accounting for expanded and collapsed rows.
The asOfTime
property should be a Unix timestamp. It resolves collisions when multiple responses
map to the same row. The response with the later asOfTime
takes precedence. Conflicts can occur
because the server data source is asynchronous, and responses may arrive out of order.
The path
, start
, and end
properties correspond to the properties on the DataRequest
interface.
These may be changed in the server response, but doing so is generally not recommended.
Leaf Row Data
Leaf row data uses the DataResponseLeafItem
type (see the
API reference). Its TypeScript definition is
shown below:
export interface DataResponseLeafItem {readonly kind: "leaf";readonly id: string;readonly data: any;}
Like the DataResponse
type, the DataResponseLeafItem
also has a kind
property. This must be
"leaf"
. LyteNyte Grid uses this value to determine if the response data should create a leaf
row node.
The id
value maps to the row node's id
property, and the data
in the response is associated with that row node. Each item in the data response becomes a row node.
Branch Row Data
Group (or branch) row data is represented by the DataResponseBranchItem
. LyteNyte Grid uses these
items to create row group nodes. Group nodes represent branches in
the view that may be expanded or collapsed.
The TypeScript interface for DataResponseBranchItem
is shown below. For details, see the
API reference.
export interface DataResponseBranchItem {readonly kind: "branch";readonly id: string;readonly data: any;readonly key: string | null;readonly childCount: number;}
The kind
property tells LyteNyte Grid whether the data item creates a row group node. This value
must always be "branch"
to create group nodes.
The id
property is used as the id
for the group node. The data
, typically the group's
aggregated data, is set on the group node. The key
property is also attached to the group node and
is used to place the node in the row tree maintained by the server data source. The childCount
property is required and indicates how many child nodes the group will have.
The close mapping between DataResponseBranchItem
and the
row group node is intentional. The server response is designed to
map directly to row creation for 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
(API reference) 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.
The Data Fetcher Function
The LyteNyte Grid server data source requires a dataFetcher
function. This function is the core of
data loading. The server data source calls it whenever the view changes, passing the data 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>({dataFetcher: (params: DataFetcherParams<MyDataType>,): Promise<(DataResponse | DataResponsePinned)[]> => {return Server(params.requests);},});
The dataFetcher
function receives a params
object, which includes more than the data requests for
the current grid view. This object is described by the DataFetcherParams
type
(API reference), whose TypeScript definition is
shown below:
export interface DataFetcherParams<T> {readonly grid: Grid<T>;readonly requests: DataRequest[];readonly reqTime: number;readonly model: DataRequestModel<T>;}
The dataFetcher
returns a Promise
of type (DataResponse | DataResponsePinned)[]
. This means
LyteNyte Grid expects an array of responses, not a single one. This design supports requesting data in
slices. The dataFetcher
implementation decides how best to retrieve these items.
The grid
property is a reference to the current grid state. It is provided as a convenience if the
dataFetcher
needs extra context when sending requests, such as the current row selection.
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 configuration state that affects the view, such as filters,
sorting, or row grouping. The full interface is shown below, but see the
API reference for details on each property.
export interface DataRequestModel<T> {readonly sorts: SortModelItem<T>[];readonly filters: Record<string, FilterModelItem<T>>;readonly filtersIn: Record<string, FilterIn>;readonly quickSearch: string | null;readonly groups: RowGroupModelItem<T>[];readonly groupExpansions: Record<string, boolean | undefined>;readonly aggregations: Record<string, { fn: AggModelFn<T> }>;readonly pivotGroupExpansions: Record<string, boolean | undefined>;readonly pivotMode: boolean;readonly pivotModel: ColumnPivotModel<T>;}
Next Steps
There are more parts to this functionality, but these are covered in dedicated guides. See the guides below for detailed coverage of the server data source and example usages:
- Server Row Data: shows how to fetch server data in slices.
- Server Row Sorting: explains server-side sorting and how it is displayed client-side.
- Server Row Filtering: covers server-side filtering, including advanced features such as in filters (tree set filters) and quick search filters.
- Optimistic Loading: explores LyteNyte Grid's optimistic loading for pre-fetching data, providing a responsive client-side experience.