Querying
Fetch data on the server with the client from createPyloServer or createPyloNode, or in Client
Components with the React Query hooks. All of them share the same select and filter API.
Server
List
app/projects/page.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
import { pylo } from '@/lib/pylo';
const { data, pagination } = await pylo.project.list({
select: {
id: true,
name: true,
created_at: true,
},
pagination: { page: 1, per_page: 20 },
});
// data: Array<{ id: string; name: string | null; created_at: string }>
// pagination: { total, current_page, per_page, last_page, has_more_pages }Omit select to get all scalar fields.
By ID
example.ts
1
2
3
4
5
6
7
8
9
10
11
const project = await pylo.project.byId('project-uuid', {
select: {
id: true,
name: true,
customer: {
select: { id: true, name: true },
},
},
});
// Returns null if not foundClient hooks
usePyloList
components/project-list.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
'use client';
import { pylo } from "@/lib/pylo-hooks";
export function ProjectList() {
const { data, pagination, isLoading, error } = pylo.usePyloList('project', {
select: { id: true, name: true, created_at: true },
pagination: { page: 1, per_page: 20 },
filter: {
sortby: [{ field: 'created_at', order: 'desc' }],
},
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{data?.map((project) => (
<div key={project.id}>{project.name}</div>
))}
<p>Page {pagination?.current_page} of {pagination?.last_page}</p>
</div>
);
}| Field | Type | Description |
|---|---|---|
data | T[] | undefined | Entities matching the select |
pagination | PaginationData | undefined | Pagination metadata |
isLoading | boolean | True while the initial request runs |
error | Error | null | Error if the request failed |
refetch | () => void | Trigger a refetch |
usePyloById
Disabled while id is null or undefined.
components/project-detail.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
'use client';
import { pylo } from "@/lib/pylo-hooks";
export function ProjectDetail({ projectId }: { projectId: string }) {
const { data: project, isLoading } = pylo.usePyloById('project', projectId, {
select: {
id: true,
name: true,
customer: { select: { id: true, name: true } },
},
});
if (isLoading) return <div>Loading...</div>;
if (!project) return <div>Not found</div>;
return (
<div>
<h1>{project.name}</h1>
<p>Customer: {project.customer?.data.name}</p>
</div>
);
}usePyloInfiniteList
Infinite scrolling built on useInfiniteQuery.
components/infinite-list.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
'use client';
import { pylo } from "@/lib/pylo-hooks";
export function InfiniteProjectList() {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } =
pylo.usePyloInfiniteList('project', {
perPage: 20,
select: { id: true, name: true },
filter: {
sortby: [{ field: 'created_at', order: 'desc' }],
},
});
if (isLoading) return <div>Loading...</div>;
return (
<div>
{data?.data.map((project) => (
<div key={project.id}>{project.name}</div>
))}
{hasNextPage && (
<button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}>
{isFetchingNextPage ? 'Loading...' : 'Load more'}
</button>
)}
</div>
);
}Select
You get back the fields you set to true, and the result type matches that selection.
example.ts
1
2
select: { id: true, name: true }
// -> { id: string; name: string | null }Relations
Include relations with a nested select:
example.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
select: {
id: true,
// hasOne: pick specific fields
customer: {
select: { id: true, name: true },
},
// hasMany: with filter and pagination
invoices: {
select: { id: true, amount_net: true },
pagination: { per_page: 5 },
filter: {
sortby: [{ field: 'created_at', order: 'desc' }],
},
},
}Response shapes:
- hasOne (ManyToOne, OneToOne):
{ data: { ... } } | null - hasMany (OneToMany, ManyToMany):
{ data: [...], pagination: { ... } }
Error handling
The server client throws PyloError:
example.ts
1
2
3
4
5
6
7
8
9
10
import { PyloError } from '@pylo/nextjs';
try {
const { data } = await pylo.project.list();
} catch (error) {
if (error instanceof PyloError) {
console.error(error.message);
console.error(error.graphqlErrors);
}
}The hooks return an error state instead of throwing.