@bildit-platform/nextjs-api
v0.5.2
Published
BILDIT CMS API bindings for Next.js applications
Readme
RemoteConnector API Documentation
The RemoteConnector class provides a comprehensive interface for interacting with the BILDIT CMS API. It supports both live API calls and CDN-based data fetching with automatic fallback mechanisms.
Table of Contents
- Installation
- Configuration
- API Methods
- Data Sources
- Error Handling
- TypeScript Support
- Caching
- Cache Examples
Installation
npm install @bildit-platform/nextjs-apiConfiguration
import { RemoteConnector } from '@bildit-platform/nextjs-api'
const connector = new RemoteConnector({
key: 'your-app-key',
baseURL: 'https://your-cms-api.com',
appCheckToken: 'optional-firebase-app-check-token',
timeout: 30000, // optional, defaults to 30 seconds
onResponseFulfilled: (response) => response, // optional response interceptor
onResponseRejected: (error) => error, // optional error interceptor
})Configuration Options
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| key | string | ✅ | Your application key for API authentication |
| baseURL | string | ✅ | Base URL of your CMS API |
| appCheckToken | string | ❌ | Firebase App Check token for additional security |
| timeout | number | ❌ | Request timeout in milliseconds (default: 30000) |
| onResponseFulfilled | function | ❌ | Response interceptor for successful requests |
| onResponseRejected | function | ❌ | Response interceptor for failed requests |
API Methods
Configuration API
getConfig(params?)
Retrieves global application configuration.
const config = await connector.getConfig({
apiVersion: 'v1_2' // optional
})Parameters:
apiVersion(optional): API version to use
Returns: Remote.Config
{
useRemoteComponent: boolean
}Components API
getComponent(params)
Retrieves a remote component by path and version.
const component = await connector.getComponent({
path: '/components/header',
version: '1.0.0',
platform: 'ios', // optional: 'ios' | 'android'
apiVersion: 'v1_2' // optional
})Parameters:
path(required): Component pathversion(optional): Component versionplatform(optional): Target platformapiVersion(optional): API version to use
Returns: Remote.Component
{
id: string
path: string
version: string
code: string
}Screens API
getScreen(params)
Retrieves a screen configuration object.
const screen = await connector.getScreen({
name: 'home',
version: '1.0.0',
platform: 'ios', // optional: 'ios' | 'android'
apiVersion: 'v1_2' // optional
})Parameters:
name(required): Screen nameversion(optional): Screen versionplatform(optional): Target platformapiVersion(optional): API version to use
Returns: Remote.Screen<C>
{
name: string
version: string
config: C // Generic config object
}Categories API
getCategories(params)
Retrieves all categories from the CMS.
const categories = await connector.getCategories({
apiVersion: 'v1_2' // optional
})Parameters:
apiVersion(optional): API version to use
Returns: { [key: string]: Remote.Category<T> }
{
[categoryId: string]: {
id: string
name: string
parentId: string
showInMenu: boolean
headerMenuBanner: string
alternateCategoryID?: string
categories?: Category<T>[]
order: number
description?: string
}
}Web Banners API
getWebBanners(params?)
Retrieves web banners with support for both live API and CDN sources.
const banners = await connector.getWebBanners({
// Source configuration
source: 'auto', // 'auto' | 'live' | 'cdn'
customerBucketId: 'your-bucket-id',
appId: 'your-app-id',
// Filtering options
location: '/home',
category: 'promotions',
customerGroup: 'premium',
date: '2024-01-15',
published: true,
archived: false,
// CDN configuration
type: 'banners', // 'banners' | 'homepage' | 'globaldata'
liveUrl: 'https://custom-api.com/banners',
// Caching
etag: 'previous-etag',
lastModified: '2024-01-01T00:00:00Z',
// API version
apiVersion: 'v1_2'
})Parameters:
source(optional): Data source preference -'auto'(default),'live', or'cdn'customerBucketId(optional): Required for CDN sourceappId(optional): Required for CDN sourcelocation(optional): Filter by locationcategory(optional): Filter by categorycustomerGroup(optional): Filter by customer groupdate(optional): Filter by datepublished(optional): Filter by publication statusarchived(optional): Filter by archive statustype(optional): Dataset type for CDNliveUrl(optional): Override live API URLetag(optional): ETag for conditional requestslastModified(optional): Last-Modified header for conditional requestsapiVersion(optional): API version to use
Returns: Remote.WebBannerResult
{
codelib: string
lastUpdated: number
data: WebBanner[]
meta: {
source: 'live' | 'cdn'
etag?: string
lastModified?: string
versionKey?: string
fetchedAt: string
datasetType?: string
totalItems?: number
}
}Content API
getContentById(params)
Retrieves a specific content item by slug.
const content = await connector.getContentById({
slug: 'about-us',
category: 'company', // only available with v1_2 API
source: 'auto',
customerBucketId: 'your-bucket-id',
appId: 'your-app-id',
apiVersion: 'v1_2'
})Parameters:
slug(required): Content slugcategory(optional): Category filter (v1_2 only)source(optional): Data source preferencecustomerBucketId(optional): Required for CDN sourceappId(optional): Required for CDN sourceapiVersion(optional): API version to use
Returns: Remote.Content
getContent(params)
Retrieves content by location or category.
const content = await connector.getContent({
location: '/products',
// OR
category: 'products', // only available with v1_2 API
source: 'auto',
customerBucketId: 'your-bucket-id',
appId: 'your-app-id',
apiVersion: 'v1_2'
})Parameters:
location(optional): Filter by location (required if category not provided)category(optional): Filter by category (required if location not provided, v1_2 only)source(optional): Data source preferencecustomerBucketId(optional): Required for CDN sourceappId(optional): Required for CDN sourceapiVersion(optional): API version to use
Returns: Remote.Content[]
Content Structure:
{
id: string
code: string
createdAt: number
devices: Partial<Record<'ipad' | 'iphone' | 'android', boolean>>
name: string
slug: string
updatedAt: number
url: string
status: string
locations: string[]
categories: string[]
openInExternalBrowser: boolean
}Templates API
getCodeLib(params?)
Retrieves template entries with support for both live API and CDN sources.
const codeLib = await connector.getCodeLib({
id: 'specific-component', // optional: filter by specific ID
source: 'auto',
customerBucketId: 'your-bucket-id',
appId: 'your-app-id',
type: 'codelibrary',
etag: 'previous-etag',
lastModified: '2024-01-01T00:00:00Z',
apiVersion: 'v1_2'
})Parameters:
id(optional): Filter by specific template IDsource(optional): Data source preferencecustomerBucketId(optional): Required for CDN sourceappId(optional): Required for CDN sourcetype(optional): Dataset type (default: 'codelibrary')etag(optional): ETag for conditional requestslastModified(optional): Last-Modified header for conditional requestsapiVersion(optional): API version to use
Returns: Remote.CodeLibraryResult
{
lastUpdated: number
data: Record<string, CodeLibraryEntry>
meta: {
source: 'live' | 'cdn'
etag?: string
lastModified?: string
versionKey?: string
fetchedAt: string
datasetType?: string
totalEntries?: number
}
}Template entry structure:
{
id: string
name: string
type?: string
description?: string
image?: string
isCustom?: boolean
code: {
compiled: string
raw?: string
[key: string]: any
}
codeType?: string
createdAt?: number
updatedAt?: number
createdBy?: Record<string, any>
updatedBy?: Record<string, any>
[key: string]: any
}Base templates API
getRemoteBaseCodelib(params?)
Retrieves the remote base templates bundle.
const baseCodelib = await connector.getRemoteBaseCodelib({
apiVersion: 'v1_2' // optional
})Parameters:
apiVersion(optional): API version to use
Returns: Remote.BaseCodelib
{
id: string
name: string
version: string
code: string
description?: string
createdAt: number
updatedAt: number
}Data Sources
The RemoteConnector supports three data source modes:
1. Live API (source: 'live')
- Fetches data directly from the CMS API
- Real-time data
- Requires API authentication
- Slower but most up-to-date
2. CDN (source: 'cdn')
- Fetches data from CDN/S3 storage
- Cached data for better performance
- Requires
customerBucketIdandappId - Faster but may have slight delays
3. Auto (source: 'auto' - default)
- Tries live API first
- Falls back to CDN if live API fails
- Best of both worlds approach
Error Handling
The RemoteConnector includes comprehensive error handling:
try {
const banners = await connector.getWebBanners({
source: 'auto',
customerBucketId: 'your-bucket-id',
appId: 'your-app-id'
})
} catch (error) {
if (error.message === 'CustomerBucketId and AppId are required for CDN fetch') {
// Handle missing CDN configuration
} else if (error.message.includes('not found')) {
// Handle not found errors
} else {
// Handle other errors
console.error('API Error:', error)
}
}Common Error Scenarios
- Missing CDN Configuration: When using
source: 'cdn'withoutcustomerBucketIdandappId - Content Not Found: When requesting content by slug that doesn't exist
- Invalid API Version: When using features not available in the specified API version
- Network Errors: Timeout or connection issues
TypeScript Support
The RemoteConnector is fully typed with TypeScript definitions:
import { RemoteConnector, Remote } from '@bildit-platform/nextjs-api'
// Type-safe method calls
const banners: Remote.WebBannerResult = await connector.getWebBanners()
const content: Remote.Content[] = await connector.getContent({ location: '/home' })
const categories: { [key: string]: Remote.Category } = await connector.getCategories()Generic Types
Many methods support generic types for custom data structures:
// Custom screen config type
interface CustomScreenConfig {
theme: 'light' | 'dark'
features: string[]
}
const screen = await connector.getScreen<CustomScreenConfig>({
name: 'home'
})
// screen.config is now typed as CustomScreenConfigBest Practices
- Use Auto Source: Default to
source: 'auto'for the best balance of performance and freshness - Implement Caching: Use
etagandlastModifiedfor efficient caching - Handle Errors Gracefully: Always wrap API calls in try-catch blocks
- Type Safety: Leverage TypeScript generics for custom data structures
- CDN Configuration: Provide
customerBucketIdandappIdwhen using CDN features - API Versioning: Use specific API versions when you need particular features
Examples
Basic Usage
import { RemoteConnector } from '@bildit-platform/nextjs-api'
const connector = new RemoteConnector({
key: 'your-app-key',
baseURL: 'https://api.bildit.com'
})
// Get all web banners
const banners = await connector.getWebBanners()
// Get content by location
const content = await connector.getContent({
location: '/products'
})
// Get a specific component
const header = await connector.getComponent({
path: '/components/header',
version: '1.0.0'
})Advanced Usage with CDN
const connector = new RemoteConnector({
key: 'your-app-key',
baseURL: 'https://api.bildit.com'
})
// Get banners from CDN with caching
const banners = await connector.getWebBanners({
source: 'cdn',
customerBucketId: 'mycompany',
appId: 'webapp',
etag: 'previous-etag-value',
lastModified: '2024-01-01T00:00:00Z'
})
// Check if data was modified
if (banners.meta.etag !== 'previous-etag-value') {
// Data was updated, process new banners
console.log('New banners available:', banners.data)
}Error Handling Example
async function loadBanners() {
try {
const banners = await connector.getWebBanners({
source: 'auto',
customerBucketId: 'mycompany',
appId: 'webapp'
})
return banners.data
} catch (error) {
console.error('Failed to load banners:', error.message)
// Fallback to empty array
return []
}
}Caching
The RemoteConnector includes a powerful caching system built on top of node-cache MultiKeyMemoryCache. This allows you to cache API responses in memory to improve performance and reduce API calls.
Basic Caching
import { RemoteConnector, withCache } from '@bildit-platform/nextjs-api'
const connector = new RemoteConnector({
key: 'your-app-key',
baseURL: 'https://api.bildit.com'
})
// Wrap any method with caching
const cachedGetWebBanners = withCache(
'getWebBanners',
connector.getWebBanners.bind(connector),
{ ttl: 600 } // Cache for 10 minutes
)
// Use the cached version
const banners = await cachedGetWebBanners({
source: 'auto',
customerBucketId: 'mycompany',
appId: 'webapp'
})Cache Options
interface CacheOptions {
/**
* Time to live in seconds (default: 300 = 5 minutes)
*/
ttl?: number
/**
* Check period in seconds (default: 60 = 1 minute)
*/
checkperiod?: number
/**
* Use clones of the cached values (default: false)
*/
useClones?: boolean
/**
* Delete expired keys (default: true)
*/
deleteOnExpire?: boolean
}Manual Cache Management
import { cache, makeCacheKey } from '@bildit-platform/nextjs-api'
// Get a value from cache
const cached = cache.get('my-key')
// Set a value in cache
cache.set('my-key', data, { ttl: 300 })
// Check if a key exists
const exists = cache.has('my-key')
// Delete a key
cache.del('my-key')
// Clear all cache
cache.flushAll()
// Get cache statistics
const stats = cache.getStats()Creating Cache Keys
import { makeCacheKey } from '@bildit-platform/nextjs-api'
// Create stable cache keys
const key1 = makeCacheKey('getWebBanners', [{ source: 'auto', location: '/home' }])
const key2 = makeCacheKey('getContent', [{ slug: 'about-us' }])Cache Examples
Example 1: Cached Connector Factory
import { RemoteConnector, withCache } from '@bildit-platform/nextjs-api'
export function createCachedConnector(options: any) {
const connector = new RemoteConnector(options)
return {
...connector,
// Cache banners for 10 minutes
getWebBanners: withCache(
'getWebBanners',
connector.getWebBanners.bind(connector),
{ ttl: 600 }
),
// Cache content for 30 minutes
getContent: withCache(
'getContent',
connector.getContent.bind(connector),
{ ttl: 1800 }
),
// Cache categories for 1 hour
getCategories: withCache(
'getCategories',
connector.getCategories.bind(connector),
{ ttl: 3600 }
),
}
}
// Usage
const cachedConnector = createCachedConnector({
key: 'your-app-key',
baseURL: 'https://api.bildit.com'
})Example 2: Conditional Caching
export function createConditionalCachedConnector(options: any) {
const connector = new RemoteConnector(options)
const cachedGetWebBanners = withCache(
'getWebBanners',
async (params: any) => {
// Longer TTL for CDN source since it's more stable
const ttl = params.source === 'cdn' ? 1800 : 300
return connector.getWebBanners(params)
},
{ ttl: 300 }
)
return {
...connector,
getWebBanners: cachedGetWebBanners,
}
}Example 3: Manual Cache Control
import { cache, makeCacheKey } from '@bildit-platform/nextjs-api'
export function createManualCacheConnector(options: any) {
const connector = new RemoteConnector(options)
return {
...connector,
async getWebBanners(params: any) {
const key = makeCacheKey('getWebBanners', [params])
// Check cache first
const cached = cache.get(key)
if (cached) {
return cached
}
// Fetch from API
const result = await connector.getWebBanners(params)
// Cache with custom TTL based on source
const ttl = params.source === 'cdn' ? 1800 : 300
cache.set(key, result, { ttl })
return result
},
// Clear specific cache entries
clearCache(type: string, params?: any) {
if (params) {
const key = makeCacheKey(type, [params])
cache.del(key)
} else {
// Clear all cache entries for this type
const keys = cache.keys().filter(key => key.startsWith(`${type}:`))
keys.forEach(key => cache.del(key))
}
},
// Clear all cache
clearAllCache() {
cache.flushAll()
},
}
}Example 4: Error Handling with Cache
export function createErrorHandlingCachedConnector(options: any) {
const connector = new RemoteConnector(options)
const cachedGetWebBanners = withCache(
'getWebBanners',
async (params: any) => {
try {
return await connector.getWebBanners(params)
} catch (error) {
// Log error but don't cache failures
console.error('Failed to fetch web banners:', error)
throw error
}
},
{ ttl: 300 }
)
return {
...connector,
getWebBanners: cachedGetWebBanners,
}
}Best Practices for Caching
Choose Appropriate TTL Values:
- Frequently changing data (banners): 5-10 minutes
- Moderately changing data (content): 30 minutes
- Rarely changing data (categories, components): 1-2 hours
Consider Data Source:
- CDN data can be cached longer than live API data
- Use conditional TTL based on source parameter
Handle Cache Invalidation:
- Provide methods to clear specific cache entries
- Consider cache warming strategies
Monitor Cache Performance:
- Use
cache.getStats()to monitor hit rates - Adjust TTL values based on usage patterns
- Use
Error Handling:
- Don't cache failed requests
- Implement proper error boundaries
