Client for Contentful's Content Delivery API
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Advanced querying capabilities for filtering, searching, and retrieving specific content with type-safe parameter validation and comprehensive query operators.
Core query parameters available for most content retrieval operations.
interface BaseQueries {
/** Limit number of results (max: 1000, default: 100) */
limit?: number;
/** Skip entries for pagination (max: 9000) */
skip?: number;
/** Order results by field (prefix with - for descending) */
order?: string;
/** Specify locale (default: default locale of space) */
locale?: string;
/** Select specific fields to return */
select?: string;
/** Include linked entries and assets (default: 1, max: 10) */
include?: number;
}Full-text search capabilities across content fields.
interface SearchQueries {
/** Full-text search across all text fields */
query?: string;
}Usage Examples:
// Basic full-text search
const searchResults = await client.getEntries({
query: "JavaScript tutorial"
});
// Search within specific content type
const blogSearchResults = await client.getEntries({
content_type: "blogPost",
query: "React hooks"
});Filter content by exact field values.
interface EqualityQueries {
/** Filter by exact field value */
[key: `fields.${string}`]: any;
/** Filter by system property */
[key: `sys.${string}`]: any;
}Usage Examples:
// Filter by field values
const featuredPosts = await client.getEntries({
content_type: "blogPost",
"fields.featured": true,
"fields.category": "Technology"
});
// Filter by system properties
const recentEntries = await client.getEntries({
"sys.createdAt[gte]": "2023-01-01T00:00:00Z"
});Check for the presence or absence of field values.
interface ExistenceQueries {
/** Check if field exists and has a value */
[key: `fields.${string}[exists]`]: boolean;
/** Check if system property exists */
[key: `sys.${string}[exists]`]: boolean;
}Usage Examples:
// Find entries with specific fields present
const entriesWithImages = await client.getEntries({
content_type: "blogPost",
"fields.featuredImage[exists]": true
});
// Find entries missing certain fields
const drafts = await client.getEntries({
content_type: "blogPost",
"fields.publishDate[exists]": false
});Filter content using range comparisons for numbers and dates.
interface RangeQueries {
/** Greater than */
[key: `fields.${string}[gt]`]: string | number;
/** Greater than or equal */
[key: `fields.${string}[gte]`]: string | number;
/** Less than */
[key: `fields.${string}[lt]`]: string | number;
/** Less than or equal */
[key: `fields.${string}[lte]`]: string | number;
/** System property range queries */
[key: `sys.${string}[gt]`]: string | number;
[key: `sys.${string}[gte]`]: string | number;
[key: `sys.${string}[lt]`]: string | number;
[key: `sys.${string}[lte]`]: string | number;
}Usage Examples:
// Date range queries
const recentPosts = await client.getEntries({
content_type: "blogPost",
"fields.publishDate[gte]": "2023-01-01",
"fields.publishDate[lte]": "2023-12-31"
});
// Numeric range queries
const expensiveProducts = await client.getEntries({
content_type: "product",
"fields.price[gt]": 100,
"fields.price[lte]": 1000
});Filter content using set operations (in/nin).
interface SetQueries {
/** Field value is in the provided array */
[key: `fields.${string}[in]`]: string[];
/** Field value is not in the provided array */
[key: `fields.${string}[nin]`]: string[];
/** System property set queries */
[key: `sys.${string}[in]`]: string[];
[key: `sys.${string}[nin]`]: string[];
}Usage Examples:
// Include multiple categories
const techAndDesignPosts = await client.getEntries({
content_type: "blogPost",
"fields.category[in]": ["Technology", "Design", "Development"]
});
// Exclude specific content
const nonDraftEntries = await client.getEntries({
content_type: "blogPost",
"fields.status[nin]": ["draft", "archived"]
});Filter arrays and check for matches within array fields.
interface SubsetQueries {
/** All array items match the query */
[key: `fields.${string}[all]`]: string[];
/** Some array items match the query */
[key: `fields.${string}[in]`]: string[];
/** No array items match the query */
[key: `fields.${string}[nin]`]: string[];
}Usage Examples:
// Entries with all specified tags
const wellTaggedPosts = await client.getEntries({
content_type: "blogPost",
"fields.tags[all]": ["javascript", "tutorial"]
});
// Entries with some of the specified tags
const relatedPosts = await client.getEntries({
content_type: "blogPost",
"fields.tags[in]": ["react", "vue", "angular"]
});Filter content by linked entries and assets.
interface ReferenceQueries {
/** Links to specific entry */
[key: `fields.${string}.sys.id`]: string;
/** Links to entry of specific content type */
[key: `fields.${string}.sys.contentType.sys.id`]: string;
/** Links to any of the specified entries */
[key: `fields.${string}[in]`]: string[];
/** Doesn't link to any of the specified entries */
[key: `fields.${string}[nin]`]: string[];
}Usage Examples:
// Find entries linked to specific author
const authorPosts = await client.getEntries({
content_type: "blogPost",
"fields.author.sys.id": "author-id"
});
// Find entries linked to authors of specific type
const postsWithPersonAuthors = await client.getEntries({
content_type: "blogPost",
"fields.author.sys.contentType.sys.id": "person"
});
// Find entries linked to any of several categories
const categorizedPosts = await client.getEntries({
content_type: "blogPost",
"fields.category[in]": ["cat1", "cat2", "cat3"]
});Filter content by geographical proximity (for Location fields).
interface LocationQueries {
/** Find entries near coordinates */
[key: `fields.${string}[near]`]: string; // "lat,lon"
/** Find entries within bounding box */
[key: `fields.${string}[within]`]: string; // "lat1,lon1,lat2,lon2"
}Usage Examples:
// Find locations near New York City
const nearbyLocations = await client.getEntries({
content_type: "venue",
"fields.location[near]": "40.7128,-74.0060"
});
// Find locations within a bounding box
const locationsInArea = await client.getEntries({
content_type: "venue",
"fields.location[within]": "40.7,-74.1,40.8,-73.9"
});Control result ordering with multiple fields and directions.
interface OrderQueries {
/** Order by field (prefix with - for descending) */
order?: string | string[];
}Usage Examples:
// Order by single field
const orderedPosts = await client.getEntries({
content_type: "blogPost",
order: "-fields.publishDate" // Descending
});
// Multiple ordering criteria
const complexOrdered = await client.getEntries({
content_type: "blogPost",
order: ["fields.featured", "-fields.publishDate"]
});
// Order by system properties
const byCreation = await client.getEntries({
order: "-sys.createdAt"
});Optimize responses by selecting only needed fields.
interface SelectQueries {
/** Comma-separated list of fields to include */
select?: string;
}Usage Examples:
// Select only specific fields
const minimalEntries = await client.getEntries({
content_type: "blogPost",
select: "fields.title,fields.slug,sys.id"
});
// Select nested fields
const authorNames = await client.getEntries({
content_type: "blogPost",
select: "fields.title,fields.author.fields.name"
});
// Select system fields
const systemInfo = await client.getEntries({
select: "sys.id,sys.createdAt,sys.updatedAt"
});// Complex query combining multiple filters
const complexQuery = await client.getEntries({
content_type: "blogPost",
query: "JavaScript", // Full-text search
"fields.category": "Technology", // Exact match
"fields.publishDate[gte]": "2023-01-01", // Range query
"fields.featured": true, // Boolean filter
"fields.tags[in]": ["tutorial", "beginner"], // Set query
"fields.author[exists]": true, // Existence check
order: ["-fields.publishDate", "fields.title"], // Multi-field ordering
limit: 20, // Pagination
skip: 0,
include: 2 // Include linked content
});// Implement pagination
async function getAllEntries(contentType: string, batchSize: number = 100) {
const allEntries = [];
let skip = 0;
let hasMore = true;
while (hasMore) {
const batch = await client.getEntries({
content_type: contentType,
limit: batchSize,
skip: skip
});
allEntries.push(...batch.items);
skip += batchSize;
hasMore = batch.items.length === batchSize;
}
return allEntries;
}// Build queries dynamically
function buildQuery(filters: Record<string, any>): any {
const query: any = {};
Object.entries(filters).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== '') {
if (Array.isArray(value)) {
query[`${key}[in]`] = value;
} else if (typeof value === 'object' && value.operator) {
query[`${key}[${value.operator}]`] = value.value;
} else {
query[key] = value;
}
}
});
return query;
}
// Usage
const dynamicQuery = buildQuery({
content_type: "blogPost",
"fields.category": "Technology",
"fields.publishDate": { operator: "gte", value: "2023-01-01" },
"fields.tags": ["javascript", "tutorial"]
});
const results = await client.getEntries(dynamicQuery);// Validate query parameters
function validateQuery(query: any): string[] {
const errors = [];
if (query.limit && (query.limit < 1 || query.limit > 1000)) {
errors.push("Limit must be between 1 and 1000");
}
if (query.skip && query.skip > 9000) {
errors.push("Skip cannot exceed 9000");
}
if (query.include && (query.include < 0 || query.include > 10)) {
errors.push("Include must be between 0 and 10");
}
return errors;
}
// Use validation
const query = {
content_type: "blogPost",
limit: 50,
include: 2
};
const validationErrors = validateQuery(query);
if (validationErrors.length > 0) {
console.error("Query validation errors:", validationErrors);
} else {
const results = await client.getEntries(query);
}