strapi-query
v0.5.6
Published
Schema-first typed query client for Strapi REST APIs.
Maintainers
Readme
strapi-query
Schema-first typed query client for Strapi REST APIs.
strapi-query keeps runtime entity types clean while deriving relation-aware filters,
populate options, and response types from a schema registry.
Install
pnpm add strapi-queryDefine a Schema
import { collection, defineSchema, entity, many, one, single } from 'strapi-query';
interface Article {
id: number;
documentId: string;
title: string;
slug: string;
content: string;
publishedAt: string;
}
interface Theme {
id: number;
documentId: string;
name: string;
uid: string;
}
interface UploadFile {
id: number;
documentId: string;
url: string;
alternativeText: string | null;
}
interface HomePage {
id: number;
documentId: string;
}
export const schema = defineSchema({
article: collection('articles', {
entity: entity<Article>(),
relations: {
cover: one('uploadFile'),
themes: many('theme')
}
}),
theme: collection('themes', { entity: entity<Theme>() }),
uploadFile: collection('upload-files', { entity: entity<UploadFile>() }),
homePage: single('home-page', {
entity: entity<HomePage>(),
relations: {
featuredArticle: one('article'),
trendingArticles: many('article')
}
})
});Query Strapi
import { createStrapiClient } from 'strapi-query';
import { schema } from './schema';
const strapi = createStrapiClient({
endpoint: 'https://cms.example.com',
token: process.env.STRAPI_API_TOKEN,
schema
});
const articles = await strapi.collection('article').findMany({
filters: {
slug: { $eq: 'best-reits-singapore' },
themes: { uid: 'reits' }
},
fields: ['title', 'slug', 'publishedAt'],
populate: {
cover: true,
themes: true
},
sort: ['publishedAt:desc'],
pagination: { page: 1, pageSize: 10 },
publicationFilter: 'has-published-version'
});The response type is inferred from the schema and populate object. Runtime records
do not contain fake relation metadata.
Generate a Schema
strapi-query can generate the TypeScript entity interfaces, relations, and
schema registry directly from Strapi schema files:
strapi-query generate --strapi-schema ./src --out ./src/strapi-schema.tsPass a Strapi project src directory to discover content type
schema.json files and component JSON files automatically. You can also pass
individual files or repeat --strapi-schema.
If your Strapi project has the GraphQL plugin enabled, you can still generate from GraphQL introspection.
strapi-query generate --graphql-url http://localhost:1337/graphql --out ./src/strapi-schema.tsYou can also generate from a saved introspection result:
strapi-query generate --graphql ./graphql-introspection.json --out ./src/strapi-schema.tsThe generator discovers resources from GraphQL Query fields, maps GraphQL object
types to TypeScript interfaces, and turns object/list fields that point at other
resources into one() and many() relations. Generated resource paths follow
Strapi REST conventions, such as articles, home-page, and upload/files.
By default, generated interfaces use an optimistic REST-friendly nullability mode:
scalar and enum fields are emitted as required non-null properties, while
object-valued component fields can still be null. To mirror GraphQL
introspection nullability exactly, pass --nullability graphql.
Type Helpers
import type { Entity, Populated } from 'strapi-query';
import { schema } from './schema';
type PlainArticle = Entity<typeof schema, 'article'>;
type ArticleCard = Populated<typeof schema, 'article', { cover: true; themes: true }>;Scope
This is intentionally not an ORM. It does not model persistence, lazy loading, transactions, or identity maps. It is a typed REST query boundary for Strapi.
