Laizy CMS
Client

Queries

Reference for findMany, findById, and count methods in the generated Laizy TypeScript client.

Queries

The generated client provides three query methods for each content model: findMany() for listing entries, findById() for fetching a single entry, and count() for counting entries. All methods are fully typed and return data matching your schema.

Setup

Before using any query methods, create a client instance:

import { LaizyClient } from './generated/laizy';
import { ManagementClient } from '@/lib/management-client';

const managementClient = new ManagementClient({
  baseUrl: process.env.NEXT_PUBLIC_LAIZY_BASE_URL!,
  apiToken: process.env.NEXT_PUBLIC_LAIZY_TOKEN!,
  projectId: 'your-project-id',
});

const client = new LaizyClient(managementClient);

findMany

Fetch multiple content entries for a model. Returns an array of fully typed objects.

Signature

async findMany(options?: FindManyOptions<T>): Promise<T[]>

Basic Usage

// Fetch all blog posts
const posts = await client.blogPost.findMany();

// Fetch all authors
const authors = await client.author.findMany();

With Pagination

Use limit and offset for pagination:

// First page (10 entries)
const page1 = await client.blogPost.findMany({
  limit: 10,
  offset: 0,
});

// Second page
const page2 = await client.blogPost.findMany({
  limit: 10,
  offset: 10,
});

Options

interface FindManyOptions<T> {
  where?: Partial<T>
  select?: Partial<Record<keyof T, boolean>>
  limit?: number
  offset?: number
}
OptionTypeDescriptionDefault
limitnumberMaximum entries to return50
offsetnumberNumber of entries to skip0
wherePartial<T>Filter criteria-
selectPartial<Record<keyof T, boolean>>Field selection-

Return Type

Returns an array of the model's type with all fields populated, including system fields:

const posts = await client.blogPost.findMany();
// Type: BlogPost[]

// Each post has this shape:
// {
//   title: string
//   content: string
//   status: string
//   slug: string
//   id: string
//   createdAt: Date
//   updatedAt: Date
// }

Empty Results

If no entries exist, findMany() returns an empty array:

const posts = await client.blogPost.findMany();
console.log(posts.length); // 0

findById

Fetch a single content entry by its unique ID. Returns the entry or null if not found.

Signature

async findById(id: string): Promise<T | null>

Basic Usage

const post = await client.blogPost.findById('abc123');

if (post) {
  console.log(post.title);  // Type-safe access
  console.log(post.slug);
} else {
  console.log('Post not found');
}

Return Type

Returns either a fully typed model object or null:

const post = await client.blogPost.findById('abc123');
// Type: BlogPost | null

Error Handling

The method returns null for missing entries instead of throwing an error. Network or authentication errors are thrown as exceptions:

try {
  const post = await client.blogPost.findById('abc123');
  if (!post) {
    // Entry does not exist
    return notFound();
  }
  return post;
} catch (error) {
  // Network error, auth error, or server error
  console.error('Failed to fetch post:', error);
}

The client automatically handles NOT_FOUND errors from the API by returning null instead of throwing. This makes it easy to handle missing entries without try/catch blocks for the common case.

count

Count the total number of entries for a model. Returns a number.

Signature

async count(options?: { where?: Partial<T> }): Promise<number>

Basic Usage

const totalPosts = await client.blogPost.count();
console.log(`Total posts: ${totalPosts}`);

const totalAuthors = await client.author.count();
console.log(`Total authors: ${totalAuthors}`);

Return Type

Returns a plain number:

const count = await client.blogPost.count();
// Type: number

Practical Examples

Paginated Blog List

import { LaizyClient, type BlogPost } from './generated/laizy';

const PAGE_SIZE = 10;

async function getBlogPage(page: number): Promise<{
  posts: BlogPost[];
  total: number;
  hasMore: boolean;
}> {
  const offset = (page - 1) * PAGE_SIZE;

  const [posts, total] = await Promise.all([
    client.blogPost.findMany({ limit: PAGE_SIZE, offset }),
    client.blogPost.count(),
  ]);

  return {
    posts,
    total,
    hasMore: offset + posts.length < total,
  };
}

Single Entry Page

async function getBlogPost(id: string): Promise<BlogPost | null> {
  return client.blogPost.findById(id);
}

Dashboard Statistics

async function getDashboardStats() {
  const [postCount, authorCount, heroCount] = await Promise.all([
    client.blogPost.count(),
    client.author.count(),
    client.heroSection.count(),
  ]);

  return { postCount, authorCount, heroCount };
}

Fetching All Content for Static Site Generation

async function getAllPosts(): Promise<BlogPost[]> {
  const total = await client.blogPost.count();
  const allPosts: BlogPost[] = [];

  // Fetch in batches of 50
  for (let offset = 0; offset < total; offset += 50) {
    const batch = await client.blogPost.findMany({
      limit: 50,
      offset,
    });
    allPosts.push(...batch);
  }

  return allPosts;
}

Data Transformation

The client transforms raw API responses into typed objects. The API returns content data as a flat data object plus metadata, and the client merges them:

// Raw API response:
// {
//   id: "abc123",
//   modelName: "BlogPost",
//   data: { title: "Hello", content: "World", slug: "hello" },
//   status: "published",
//   createdAt: "2024-01-15T10:30:00.000Z",
//   updatedAt: "2024-01-15T10:30:00.000Z"
// }

// Client transforms to:
// {
//   title: "Hello",
//   content: "World",
//   slug: "hello",
//   id: "abc123",
//   createdAt: Date,
//   updatedAt: Date
// }

The data fields are spread at the top level alongside the system fields for a flat, type-safe interface.

Content Status

The generated client queries all content regardless of status (draft, published, archived). If you need to filter by status, use the ManagementClient directly:

// Using ManagementClient for status filtering
const publishedPosts = await managementClient.listContentData({
  modelName: 'BlogPost',
  status: 'published',
  limit: 50,
  offset: 0,
});

Frontend tokens (scope: content:read) automatically filter to published content only. Admin tokens return all content regardless of status.

Next Steps

On this page