@mybe/sdk
v1.1.2
Published
A TypeScript SDK for fetching content from Mybe CMS.
Downloads
131
Readme
Mybe CMS SDK
A TypeScript SDK for fetching content from Mybe CMS.
Installation
npm install @mybe/sdkFeatures
- ✅ Zero Dependencies - Uses native fetch API
- ✅ TypeScript Support - Full type safety with TypeScript
- ✅ Environment Support - Query content from different environments (master, staging, development)
- ✅ Error Handling - Custom error classes for better error handling
- ✅ Pagination Support - Built-in pagination for large datasets
- ✅ Status Filtering - Filter content by status (draft, published, archived)
- ✅ Locale Filtering - Filter content by locale for multi-language support
- ✅ GraphQL Support - Powerful GraphQL API for flexible data querying
Quick Start
import { MybeSDK } from '@mybe/sdk';
// Initialize the SDK
const sdk = new MybeSDK({
apiKey: 'your-api-key'
});
// Fetch a single content entry
const content = await sdk.getContent('content-id');
// Fetch content by type with filters
const contentList = await sdk.getContentByType('content-type-id', {
status: 'published',
limit: 10
});Configuration
Basic Configuration
const sdk = new MybeSDK({
apiKey: 'your-api-key'
// Defaults to 'master' environment
});Environment Configuration
Mybe CMS supports multiple environments for content isolation. Each SDK instance is locked to a specific environment.
// Production environment (default)
const prodClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'master' // or omit for default
});
// Staging environment
const stagingClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'staging'
});
// Development environment
const devClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'development'
});
// Custom environment (by slug or UUID)
const customClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'my-custom-env'
});Environment Best Practices:
- Master Environment - Your production content (default)
- Staging Environment - Test changes before production
- Development Environment - Active development work
- Custom Environments - Feature branches, testing, etc.
Important: Each client instance is locked to its environment. To query different environments, create separate client instances.
// ✅ Correct: Separate clients for different environments
const prodPosts = await prodClient.getContentByType('blog-post-id');
const stagingPosts = await stagingClient.getContentByType('blog-post-id');
// ❌ Incorrect: Cannot switch environments on the same client
// You must create a new client instanceCustom Base URL (Optional)
const sdk = new MybeSDK({
apiKey: 'your-api-key',
baseUrl: 'https://custom-api.example.com/api/v1',
environment: 'staging'
});Getting Current Environment
const sdk = new MybeSDK({
apiKey: 'your-api-key',
environment: 'staging'
});
console.log(sdk.getEnvironment()); // 'staging'API Reference
Content Models (Content Types)
getContentModels(projectId: string)
Get all content models for a project.
const contentModels = await sdk.getContentModels('project-id');Returns: Promise<ContentType[]>
getContentModel(contentTypeId: string)
Get a specific content model by ID.
const contentModel = await sdk.getContentModel('content-type-id');Returns: Promise<ContentType>
Content Entries
getContent(contentId: string)
Get a single content entry by ID.
const content = await sdk.getContent('content-id');Returns: Promise<ContentEntry>
getContentByType(contentTypeId: string, options?: ContentFilterOptions)
Get all content entries for a specific content type.
const result = await sdk.getContentByType('content-type-id', {
status: 'published',
limit: 20,
lastKey: 'pagination-key' // For pagination
});
console.log(result.data); // Array of content entries
console.log(result.pagination.hasMore); // Boolean
console.log(result.pagination.lastEvaluatedKey); // For next pageOptions:
status?: 'draft' | 'published' | 'archived'- Filter by statuslocale?: string- Filter by locale (e.g., 'en-US', 'bn-BD', 'fr-FR', 'es-ES')limit?: number- Number of items per pagelastKey?: string- Pagination key from previous response
Returns: Promise<ContentListResponse>
getContentByProject(projectId: string, options?: ContentFilterOptions)
Get all content entries for a project.
const result = await sdk.getContentByProject('project-id', {
status: 'published',
limit: 20
});Options:
status?: 'draft' | 'published' | 'archived'- Filter by statuslocale?: string- Filter by locale (e.g., 'en-US', 'bn-BD', 'fr-FR', 'es-ES')limit?: number- Number of items per pagelastKey?: string- Pagination key from previous response
Returns: Promise<ContentListResponse>
Pagination Example
let lastKey: string | undefined;
let allContent: ContentEntry[] = [];
do {
const result = await sdk.getContentByType('content-type-id', {
status: 'published',
limit: 50,
lastKey: lastKey ? JSON.stringify(result.pagination.lastEvaluatedKey) : undefined
});
allContent = [...allContent, ...result.data];
lastKey = result.pagination.hasMore
? JSON.stringify(result.pagination.lastEvaluatedKey)
: undefined;
} while (lastKey);
console.log(`Fetched ${allContent.length} total items`);Error Handling
The SDK provides custom error classes for better error handling:
import {
MybeSDK,
NotFoundError,
UnauthorizedError,
ValidationError,
ServerError
} from '@mybe/sdk';
try {
const content = await sdk.getContent('content-id');
} catch (error) {
if (error instanceof NotFoundError) {
console.error('Content not found');
} else if (error instanceof UnauthorizedError) {
console.error('Invalid API key');
} else if (error instanceof ValidationError) {
console.error('Validation error:', error.message);
} else if (error instanceof ServerError) {
console.error('Server error:', error.message);
} else {
console.error('Unknown error:', error);
}
}Error Types
MybeSDKError- Base error classNotFoundError- Resource not found (404)UnauthorizedError- Invalid API key (401)ForbiddenError- Insufficient permissions (403)ValidationError- Validation failed (400)ServerError- Internal server error (500)
TypeScript Types
The SDK exports all TypeScript types for your convenience:
import type {
ContentType,
ContentEntry,
ContentFilterOptions,
PaginationResponse,
APIResponse,
ContentListResponse
} from '@mybe/sdk';ContentType
interface ContentType {
id: string;
project_id: string;
name: string;
slug: string;
description?: string;
created_at: string;
updated_at: string;
}ContentEntry
interface ContentEntry {
id: string;
content_type_id: string;
project_id: string;
slug?: string;
status: 'draft' | 'published' | 'archived';
data: Record<string, any>;
locale?: string;
created_by: string;
updated_by?: string;
published_at?: string;
created_at: string;
updated_at: string;
}Examples
Environment-based Workflows
Development → Staging → Production
import { MybeSDK } from '@mybe/sdk';
// Create separate clients for each environment
const devClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'development'
});
const stagingClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'staging'
});
const prodClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'master'
});
// Development: Work with draft content
const draftPosts = await devClient.getContentByType('blog-post-id', {
status: 'draft',
limit: 10
});
// Staging: Test published content
const stagingPosts = await stagingClient.getContentByType('blog-post-id', {
status: 'published',
limit: 10
});
// Production: Serve live content
const livePosts = await prodClient.getContentByType('blog-post-id', {
status: 'published',
limit: 10
});Environment-aware Application
// Automatically select environment based on NODE_ENV
const getSDKClient = () => {
const apiKey = process.env.MYBE_API_KEY!;
switch (process.env.NODE_ENV) {
case 'production':
return new MybeSDK({ apiKey, environment: 'master' });
case 'staging':
return new MybeSDK({ apiKey, environment: 'staging' });
case 'development':
default:
return new MybeSDK({ apiKey, environment: 'development' });
}
};
const sdk = getSDKClient();
console.log(`Using environment: ${sdk.getEnvironment()}`);Preview Mode (Staging vs Production)
// Next.js example: Preview mode with environments
export async function getStaticProps({ preview = false }) {
const sdk = new MybeSDK({
apiKey: process.env.MYBE_API_KEY!,
environment: preview ? 'staging' : 'master'
});
const posts = await sdk.getContentByType('blog-post-id', {
status: preview ? 'draft' : 'published',
limit: 20
});
return {
props: {
posts: posts.data,
preview
},
revalidate: 60
};
}Fetch Published Blog Posts
const sdk = new MybeSDK({
apiKey: 'your-api-key',
environment: 'master' // Production content
});
const posts = await sdk.getContentByType('blog-post-type-id', {
status: 'published',
limit: 10
});
posts.data.forEach(post => {
console.log(post.data.title);
console.log(post.data.content);
});Fetch All Content Models
const sdk = new MybeSDK({ apiKey: 'your-api-key' });
const contentModels = await sdk.getContentModels('project-id');
contentModels.forEach(model => {
console.log(`${model.name} (${model.slug})`);
});Fetch Single Content Entry
const sdk = new MybeSDK({ apiKey: 'your-api-key' });
const content = await sdk.getContent('content-entry-id');
console.log(content.data); // Your content data
console.log(content.status); // draft | published | archivedCompare Content Across Environments
const masterClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'master'
});
const stagingClient = new MybeSDK({
apiKey: 'your-api-key',
environment: 'staging'
});
// Fetch from both environments in parallel
const [masterContent, stagingContent] = await Promise.all([
masterClient.getContentByType('blog-post-id', { limit: 10 }),
stagingClient.getContentByType('blog-post-id', { limit: 10 })
]);
console.log(`Master has ${masterContent.data.length} posts`);
console.log(`Staging has ${stagingContent.data.length} posts`);
// Find differences
const masterIds = new Set(masterContent.data.map(p => p.id));
const stagingOnly = stagingContent.data.filter(p => !masterIds.has(p.id));
console.log(`${stagingOnly.length} posts only in staging`);Multi-locale Content
Fetch content in different languages using the locale filter. TypeScript will autocomplete all supported locale codes when you type locale: '':
const sdk = new MybeSDK({ apiKey: 'your-api-key' });
// Fetch English content
// TypeScript autocompletes: 'en-US', 'en-GB', 'en-CA', 'en-AU'
const englishPosts = await sdk.getContentByType('blog-post-type-id', {
status: 'published',
locale: 'en-US', // ✨ Autocomplete suggests all 31 supported locales!
limit: 10
});
// Fetch Bangla content
const banglaPosts = await sdk.getContentByType('blog-post-type-id', {
status: 'published',
locale: 'bn-BD', // ✨ Type-safe locale codes
limit: 10
});
// Fetch French content
const frenchPosts = await sdk.getContentByType('blog-post-type-id', {
status: 'published',
locale: 'fr-FR',
limit: 10
});
// Fetch Spanish content
const spanishPosts = await sdk.getContentByType('blog-post-type-id', {
status: 'published',
locale: 'es-ES',
limit: 10
});TypeScript Autocomplete Support:
The SDK provides full TypeScript autocomplete for all 31 supported locales:
import { SUPPORTED_LOCALES, type SupportedLocale } from '@mybe/sdk';
// View all supported locales
console.log(SUPPORTED_LOCALES);
// ['en-US', 'bn-BD', 'fr-FR', 'es-ES', 'de-DE', 'it-IT', ...]
// Use the type for type-safe locale handling
const userLocale: SupportedLocale = 'ja-JP'; // ✅ Valid
const invalidLocale: SupportedLocale = 'invalid'; // ❌ TypeScript error!Building a Multi-language Website:
// Get user's preferred language
const userLocale = getUserPreferredLocale(); // e.g., 'bn-BD'
// Fetch content in user's language
const localizedContent = await sdk.getContentByType('content-type-id', {
status: 'published',
locale: userLocale,
limit: 20
});
// Display localized content
localizedContent.data.forEach(item => {
console.log(item.data.title); // Title in user's language
console.log(item.metadata.locale); // e.g., 'bn-BD'
});All Supported Locales:
The SDK supports 31 locales with full TypeScript autocomplete:
- English:
en-US,en-GB,en-CA,en-AU - European:
fr-FR,es-ES,de-DE,it-IT,pt-PT,nl-NL,sv-SE,pl-PL,ru-RU - Americas:
pt-BR,es-MX,es-AR,fr-CA - Asia-Pacific:
ja-JP,ko-KR,zh-CN,zh-TW,hi-IN,th-TH,vi-VN,id-ID,ms-MY,fil-PH,bn-BD - Middle East & Africa:
ar-SA,tr-TR,he-IL
Note: When you type locale: '' in your IDE, TypeScript will show all available options!
GraphQL API
Mybe CMS provides a powerful GraphQL API for flexible data querying. Use GraphQL when you need advanced filtering, want to request specific fields only, or prefer the GraphQL query language.
Quick Start with GraphQL
import { MybeSDK } from '@mybe/sdk';
const sdk = new MybeSDK({ apiKey: 'your-api-key' });
const PROJECT_ID = 'your-project-id';
// Execute a GraphQL query
const result = await sdk.graphql(PROJECT_ID, `
query {
blogPostCollection(limit: 10, where: { status: "published" }) {
items {
id
slug
data
}
total
}
}
`);
console.log(result.blogPostCollection.items);GraphQL Method
graphql<T>(projectId: string, query: string, variables?: Record<string, any>)
Execute a GraphQL query against your project.
Parameters:
projectId- Your project IDquery- GraphQL query stringvariables- Optional query variables (recommended for dynamic queries)
Returns: Promise<T> - The data from your GraphQL query
GraphQL Examples
Basic Collection Query
const { blogPostCollection } = await sdk.graphql(PROJECT_ID, `
query {
blogPostCollection(limit: 5) {
items {
id
slug
status
data
published_at
}
total
}
}
`);
console.log(`Total posts: ${blogPostCollection.total}`);
blogPostCollection.items.forEach(post => {
console.log(post.data.title);
});Filter by Status
const { blogPostCollection } = await sdk.graphql(PROJECT_ID, `
query {
blogPostCollection(where: { status: "published" }) {
items {
id
slug
data
}
}
}
`);Get Single Entry by ID
const { blogPost } = await sdk.graphql(PROJECT_ID, `
query {
blogPost(id: "entry-123") {
id
slug
status
data
created_at
published_at
}
}
`);Using Variables (Recommended)
const result = await sdk.graphql(
PROJECT_ID,
`
query GetPostBySlug($slug: String!) {
blogPostCollection(where: { slug: $slug }) {
items {
id
slug
data
}
}
}
`,
{ slug: 'my-blog-post' }
);
const post = result.blogPostCollection.items[0];Pagination with GraphQL
// Page 1
const page1 = await sdk.graphql(PROJECT_ID, `
query {
blogPostCollection(limit: 10, skip: 0) {
items { id slug }
total
}
}
`);
// Page 2
const page2 = await sdk.graphql(PROJECT_ID, `
query {
blogPostCollection(limit: 10, skip: 10) {
items { id slug }
total
}
}
`);REST vs GraphQL - When to Use
Use REST When:
- ✅ Simple queries (get by ID, get all)
- ✅ You want straightforward API calls
- ✅ You prefer SDK helper methods
- ✅ You need full object responses
Use GraphQL When:
- ✅ Complex filtering requirements
- ✅ You need specific fields only (reduce payload size)
- ✅ Multiple queries in one request
- ✅ You want flexible, ad-hoc queries
- ✅ Your frontend uses Apollo Client or similar
Complete GraphQL Guide
For comprehensive GraphQL documentation, examples, and best practices, see:
- GraphQL API Guide - Complete GraphQL documentation
- Test Examples - Working code examples
GraphQL Schema
Your GraphQL schema is automatically generated from your content types. For example:
Content Type: "Blog Post"
Generates:
blogPost(id: ID!)- Get single entryblogPostCollection(limit, skip, where)- Get collection
Naming: Content type names are converted to camelCase (e.g., "Blog Post" → blogPost)
Requirements
- Node.js 18+ (for native fetch support)
- TypeScript 5.0+ (for development)
License
MIT
Support
For issues and questions, please visit the GitHub repository.
