Categories
The categories resource provides access to content categories on the Grapevine platform.
Overview
Categories help organize content and make it easier for users to discover relevant feeds. The categories resource provides:
- List all available categories with pagination
- Get a specific category by ID
- Convenient methods for iteration and fetching all categories
Methods
| Method | Description | Auth Required |
|---|---|---|
| list() | List categories with pagination | No |
| get() | Get category by ID | No |
| paginate() | Async generator for pagination | No |
| getAll() | Get all categories at once | No |
:::warning Deprecated Method
The client.getCategories() method is deprecated. Use client.categories.list() or client.categories.getAll() instead.
:::
Types
interface Category {
id: string; // UUID
name: string; // Display name
description: string | null;
icon_url: string | null;
is_active: boolean;
created_at: number; // Unix timestamp
updated_at: number; // Unix timestamp
}
interface ListCategoriesQuery {
page_size?: number; // Results per page (default: 20)
page_token?: string; // Pagination token
is_active?: boolean; // Filter by active status
search?: string; // Search in name/description
}list()
List categories with optional filtering and pagination.
Signature
categories.list(query?: ListCategoriesQuery): Promise<PaginatedResponse<Category>>Usage
// Get first page of categories
const result = await grapevine.categories.list();
console.log('Categories:', result.data.map(c => c.name));
// With pagination
const page1 = await grapevine.categories.list({ page_size: 10 });
if (page1.has_more) {
const page2 = await grapevine.categories.list({
page_size: 10,
page_token: page1.next_page_token
});
}
// Filter active only
const active = await grapevine.categories.list({ is_active: true });
// Search categories
const techCategories = await grapevine.categories.list({
search: 'technology'
});get()
Get a specific category by its ID.
Signature
categories.get(categoryId: string): Promise<Category>Usage
const category = await grapevine.categories.get('123e4567-e89b-12d3-a456-426614174000');
console.log('Category:', category.name);
console.log('Description:', category.description);
console.log('Active:', category.is_active);paginate()
Async generator that yields batches of categories, handling pagination automatically.
Signature
categories.paginate(
query?: ListCategoriesQuery,
pageSize?: number
): AsyncGenerator<Category[]>Usage
// Iterate through all categories
for await (const batch of grapevine.categories.paginate()) {
console.log(`Processing ${batch.length} categories`);
for (const category of batch) {
console.log(` - ${category.name}`);
}
}
// With filters
for await (const batch of grapevine.categories.paginate({ is_active: true }, 50)) {
// Process active categories
}getAll()
Convenience method to fetch all categories at once.
Signature
categories.getAll(query?: Omit<ListCategoriesQuery, 'page_token' | 'page_size'>): Promise<Category[]>Usage
// Get all categories
const allCategories = await grapevine.categories.getAll();
console.log(`Found ${allCategories.length} categories`);
// Get all active categories
const activeCategories = await grapevine.categories.getAll({ is_active: true });
// Search all categories
const techCategories = await grapevine.categories.getAll({ search: 'tech' });Complete Examples
Category Selector Component
function CategorySelector({
value,
onChange
}: {
value?: string;
onChange: (id: string) => void;
}) {
const [categories, setCategories] = useState<Category[]>([]);
useEffect(() => {
grapevine.categories.getAll({ is_active: true })
.then(setCategories);
}, []);
return (
<select value={value || ''} onChange={e => onChange(e.target.value)}>
<option value="">Select a category</option>
{categories.map(cat => (
<option key={cat.id} value={cat.id}>
{cat.name}
</option>
))}
</select>
);
}Category Browser
function CategoryBrowser() {
const [categories, setCategories] = useState<Category[]>([]);
const [selected, setSelected] = useState<Category | null>(null);
useEffect(() => {
grapevine.categories.getAll({ is_active: true })
.then(setCategories);
}, []);
return (
<div className="category-browser">
<div className="category-list">
{categories.map(cat => (
<div
key={cat.id}
className={`category-item ${selected?.id === cat.id ? 'selected' : ''}`}
onClick={() => setSelected(cat)}
>
{cat.icon_url && <img src={cat.icon_url} alt="" />}
<span>{cat.name}</span>
</div>
))}
</div>
{selected && (
<div className="category-details">
<h2>{selected.name}</h2>
{selected.description && <p>{selected.description}</p>}
<button onClick={() => {
// Navigate to feeds filtered by this category
window.location.href = `/feeds?category=${selected.id}`;
}}>
Browse Feeds
</button>
</div>
)}
</div>
);
}Find Category by Name
async function findCategoryByName(name: string): Promise<Category | null> {
const categories = await grapevine.categories.getAll();
return categories.find(
cat => cat.name.toLowerCase() === name.toLowerCase()
) || null;
}
// Usage
const techCategory = await findCategoryByName('Technology');
if (techCategory) {
console.log(`Found: ${techCategory.name} (${techCategory.id})`);
}Create Feed with Category
async function createCategorizedFeed(
feedName: string,
categoryName: string
) {
// Find the category
const categories = await grapevine.categories.getAll();
const category = categories.find(
c => c.name.toLowerCase() === categoryName.toLowerCase()
);
if (!category) {
throw new Error(`Category "${categoryName}" not found`);
}
// Create the feed
const feed = await grapevine.feeds.create({
name: feedName,
category_id: category.id,
tags: [categoryName.toLowerCase()]
});
return feed;
}
// Usage
const feed = await createCategorizedFeed('My Tech Blog', 'Technology');Category Statistics
async function getCategoryUsage() {
// Get all categories
const categories = await grapevine.categories.getAll();
// Get category stats from leaderboard
const stats = await grapevine.leaderboards.categoryStats();
// Combine data
return categories.map(cat => {
const catStats = stats.data.find(s => s.category_id === cat.id);
return {
id: cat.id,
name: cat.name,
description: cat.description,
feeds: catStats ? parseInt(catStats.total_feeds) : 0,
entries: catStats ? parseInt(catStats.total_entries) : 0,
revenue: catStats ? catStats.total_revenue : '0'
};
});
}Category Validation
When using categories with feed creation:
// ✅ Valid: No category (optional)
const feed1 = await grapevine.feeds.create({
name: 'My Feed'
});
// ✅ Valid: With valid category ID
const categories = await grapevine.categories.getAll();
const feed2 = await grapevine.feeds.create({
name: 'Categorized Feed',
category_id: categories[0].id
});
// ❌ Invalid: Empty string
const feed3 = await grapevine.feeds.create({
name: 'Bad Feed',
category_id: '' // ValidationError
});
// ❌ Invalid: Non-existent UUID
const feed4 = await grapevine.feeds.create({
name: 'Bad Feed',
category_id: '00000000-0000-0000-0000-000000000000' // API error
});Notes
- Authentication: Not required - all category endpoints are public
- Caching: Consider caching categories locally as they rarely change
- Active Filter: Use
is_active: trueto only show enabled categories
Related
- feeds.create() - Create feed with category
- feeds.list() - Filter feeds by category
- leaderboards.categoryStats() - Category statistics