Skip to content

Other SDK Classes

Beyond Nimbu.Object and Nimbu.Query, the Nimbu SDK provides specialized classes for working with specific data types and features. These classes extend the base Nimbu.Object functionality with domain-specific methods.

Nimbu.Customer

The Customer class represents customer accounts in your Nimbu site. Customers can log in, make purchases, and have associated data like orders and favorites.

Creating Customers

js
// Create a new customer
const customer = new Nimbu.Customer();
customer.set('email', '[email protected]');
customer.set('name', 'John Doe');
customer.set('password', 'securePassword123');

await customer.save();
console.log('Customer created:', customer.id);

Finding Customers

js
// Find customer by email
const query = new Nimbu.Query('customers');
query.equalTo('email', '[email protected]');
const customer = await query.first();

if (customer) {
  console.log('Found customer:', customer.get('name'));
}

Customer Properties

js
// Access customer data
const email = customer.get('email');
const name = customer.get('name');
const createdAt = customer.createdAt;

// Check customer status
const isActive = customer.get('active');
const newsletterSubscribed = customer.get('newsletter_subscribed');

Updating Customer Data

js
// Update customer information
const customer = await new Nimbu.Query('customers').get(customerId);

customer.set('phone', '+32 123 456 789');
customer.set('loyalty_points', 100);
customer.set('newsletter_subscribed', true);

await customer.save();

Customer Roles

js
// Add customer to a role
const customer = await new Nimbu.Query('customers').get(customerId);
const role = await new Nimbu.Query('roles').get(roleId);

role.getCustomers().add(customer);
await role.save();

// Check if customer has a role
const customerRoles = customer.relation('roles');
const roles = await customerRoles.query().collection().fetch();

console.log(`Customer has ${roles.length} roles`);

Customer Orders

js
// Get customer's orders
const customer = await new Nimbu.Query('customers').get(customerId);
const orders = customer.relation('orders');

const customerOrders = await orders.query()
  .descending('created_at')
  .limit(10)
  .collection()
  .fetch();

console.log(`Found ${customerOrders.length} orders`);

Nimbu.Collection

The Collection class is a utility for working with custom content types (channels) in Nimbu.

Querying Collections

js
// Query a custom collection
const Collection = Nimbu.Object.extend('blog_posts');
const query = new Nimbu.Query(Collection);

query.equalTo('published', true);
query.descending('published_at');
query.limit(10);

const posts = await query.collection().fetch();

Creating Collection Entries

js
// Create a new blog post
const BlogPost = Nimbu.Object.extend('blog_posts');
const post = new BlogPost();

post.set('title', 'My First Blog Post');
post.set('content', 'This is the content of my post');
post.set('published', true);
post.set('published_at', new Date());

await post.save();

Collection with Custom Fields

js
// Work with custom fields
const entry = new Nimbu.Object('projects');

entry.set('project_name', 'New Website');
entry.set('project_status', 'in_progress');
entry.set('project_deadline', new Date('2024-12-31'));
entry.set('project_tags', ['web', 'design', 'development']);

await entry.save();

Nimbu.Product

The Product class provides specialized methods for e-commerce products.

Product Queries

js
// Find active products
const query = new Nimbu.Query('products');
query.equalTo('active', true);
query.greaterThan('stock', 0);
query.ascending('name');

const products = await query.collection().fetch();

Product Properties

js
const product = await new Nimbu.Query('products').get(productId);

// Basic properties
const name = product.get('name');
const price = product.get('price');
const stock = product.get('stock');
const sku = product.get('sku');

// Product attributes
const description = product.get('description');
const category = product.get('category');
const tags = product.get('tags');
const active = product.get('active');

Product Variants

js
// Access product variants
const product = await new Nimbu.Query('products').get(productId);
const variants = product.get('variants');

if (variants && variants.length > 0) {
  variants.forEach(variant => {
    console.log(`${variant.name}: €${variant.price}`);
  });
}

Product Stock Management

js
// Update product stock
const product = await new Nimbu.Query('products').get(productId);

// Decrement stock (atomic operation)
await product.increment('stock', -1);
await product.save();

// Check stock level
if (product.get('stock') === 0) {
  product.set('active', false);
  await product.save();
}

Product Categories

js
// Find products by category
const query = new Nimbu.Query('products');
query.equalTo('category', 'electronics');
query.equalTo('active', true);

const electronics = await query.collection().fetch();

Nimbu.Order

The Order class represents customer orders and purchases.

Order Queries

js
// Find recent orders
const query = new Nimbu.Query('orders');
query.descending('created_at');
query.limit(20);
query.include('customer');

const recentOrders = await query.collection().fetch();

recentOrders.forEach(order => {
  const customer = order.get('customer');
  console.log(`Order ${order.id} - ${customer.get('name')}`);
});

Order Properties

js
const order = await new Nimbu.Query('orders').get(orderId);

// Order details
const orderNumber = order.get('order_number');
const status = order.get('status');
const total = order.get('total');
const currency = order.get('currency');

// Order items
const items = order.get('items');
items.forEach(item => {
  console.log(`${item.quantity}x ${item.product_name} - €${item.price}`);
});

// Customer information
const customer = order.get('customer');
const shippingAddress = order.get('shipping_address');
const billingAddress = order.get('billing_address');

Order Status Management

js
// Update order status
const order = await new Nimbu.Query('orders').get(orderId);

order.set('status', 'processing');
order.set('processed_at', new Date());

await order.save();

Order Filtering

js
// Find pending orders
const query = new Nimbu.Query('orders');
query.containedIn('status', ['pending', 'processing']);
query.include('customer');

const pendingOrders = await query.collection().fetch();

console.log(`${pendingOrders.length} orders need attention`);

Nimbu.File

The File class handles file uploads and management.

Uploading Files

js
// Upload a file
const fileData = {
  name: 'document.pdf',
  data: fileBuffer, // or base64 string
  contentType: 'application/pdf'
};

const file = new Nimbu.File(fileData);
await file.save();

console.log('File uploaded:', file.url());

Attaching Files to Objects

js
// Attach file to an object
const document = new Nimbu.Object('documents');
document.set('title', 'Annual Report');
document.set('file', file);

await document.save();

// Access file later
const savedDocument = await new Nimbu.Query('documents').get(documentId);
const attachedFile = savedDocument.get('file');

console.log('Download URL:', attachedFile.url());

File Metadata

js
// Access file properties
const fileName = file.name();
const fileUrl = file.url();
const fileSize = file.get('size');
const contentType = file.get('content_type');

console.log(`File: ${fileName} (${fileSize} bytes)`);

The Gallery class manages image galleries and media collections.

Creating Galleries

js
// Create a new gallery
const gallery = new Nimbu.Object('galleries');
gallery.set('name', 'Product Photos');
gallery.set('description', 'Photos of our products');

await gallery.save();
js
// Add images to gallery
const image1 = new Nimbu.File({ name: 'product1.jpg', data: imageData1 });
const image2 = new Nimbu.File({ name: 'product2.jpg', data: imageData2 });

await image1.save();
await image2.save();

const gallery = await new Nimbu.Query('galleries').get(galleryId);
const images = gallery.get('images') || [];

images.push(image1, image2);
gallery.set('images', images);

await gallery.save();
js
// Find galleries
const query = new Nimbu.Query('galleries');
query.equalTo('active', true);
query.descending('created_at');

const galleries = await query.collection().fetch();

galleries.forEach(gallery => {
  const images = gallery.get('images') || [];
  console.log(`${gallery.get('name')}: ${images.length} images`);
});

Nimbu.Role

The Role class manages customer roles and permissions.

Creating Roles

js
// Create a new role
const role = new Nimbu.Object('roles');
role.set('name', 'Premium Members');
role.set('description', 'Customers with premium access');

await role.save();

Adding Customers to Roles

js
// Add customers to a role
const role = await new Nimbu.Query('roles').get(roleId);
const customer = await new Nimbu.Query('customers').get(customerId);

role.getCustomers().add(customer);
await role.save();

console.log('Customer added to role');

Querying Role Members

js
// Get all customers in a role
const role = await new Nimbu.Query('roles').get(roleId);
const customers = await role.getCustomers().list();

console.log(`Role has ${customers.length} members`);

customers.forEach(customer => {
  console.log(`- ${customer.get('name')} (${customer.get('email')})`);
});

Removing Customers from Roles

js
// Remove customer from role
const role = await new Nimbu.Query('roles').get(roleId);
const customer = await new Nimbu.Query('customers').get(customerId);

role.getCustomers().remove(customer);
await role.save();

Finding Roles by Customer

js
// Find all roles for a customer
const customer = await new Nimbu.Query('customers').get(customerId);
const roles = customer.relation('roles');

const customerRoles = await roles.query().collection().fetch();

customerRoles.forEach(role => {
  console.log(`Customer has role: ${role.get('name')}`);
});

Role-Based Access Control

js
// Check if customer has specific role
async function hasRole(customer, roleName) {
  const roles = customer.relation('roles');
  const query = roles.query();
  query.equalTo('name', roleName);
  
  const matchingRoles = await query.collection().fetch();
  return matchingRoles.length > 0;
}

// Usage
const customer = await new Nimbu.Query('customers').get(customerId);
const isPremium = await hasRole(customer, 'Premium Members');

if (isPremium) {
  console.log('Customer has premium access');
}

Nimbu.API

The API class provides direct access to the Nimbu REST API for advanced use cases.

Making API Requests

js
// GET request
const response = await Nimbu.API.get('/api/products', {
  params: {
    active: true,
    limit: 10
  }
});

console.log('Products:', response.data);

POST Requests

js
// Create resource via API
const response = await Nimbu.API.post('/api/customers', {
  data: {
    email: '[email protected]',
    name: 'John Doe'
  }
});

console.log('Created customer:', response.data);

PUT/PATCH Requests

js
// Update resource
const response = await Nimbu.API.patch(`/api/products/${productId}`, {
  data: {
    price: 29.99,
    stock: 100
  }
});

DELETE Requests

js
// Delete resource
await Nimbu.API.delete(`/api/products/${productId}`);
console.log('Product deleted');

Custom Headers

js
// Add custom headers
const response = await Nimbu.API.get('/api/custom-endpoint', {
  headers: {
    'X-Custom-Header': 'value'
  }
});

Common Patterns

Customer Registration Flow

js
async function registerCustomer(email, password, name) {
  // Check if email already exists
  const query = new Nimbu.Query('customers');
  query.equalTo('email', email.toLowerCase());
  const existing = await query.first();

  if (existing) {
    throw new Error('Email already registered');
  }

  // Create new customer
  const customer = new Nimbu.Customer();
  customer.set('email', email.toLowerCase());
  customer.set('password', password);
  customer.set('name', name);
  customer.set('active', true);

  await customer.save();

  // Add to default role
  const defaultRole = await new Nimbu.Query('roles')
    .equalTo('name', 'Customers')
    .first();

  if (defaultRole) {
    defaultRole.getCustomers().add(customer);
    await defaultRole.save();
  }

  return customer;
}

Order Processing

js
async function processOrder(orderId) {
  const order = await new Nimbu.Query('orders').get(orderId);

  // Validate stock availability
  const items = order.get('items');
  for (const item of items) {
    const product = await new Nimbu.Query('products').get(item.product_id);

    if (product.get('stock') < item.quantity) {
      throw new Error(`Insufficient stock for ${product.get('name')}`);
    }
  }

  // Update stock levels
  for (const item of items) {
    const product = await new Nimbu.Query('products').get(item.product_id);
    await product.increment('stock', -item.quantity);
    await product.save();
  }

  // Update order status
  order.set('status', 'processing');
  order.set('processed_at', new Date());
  await order.save();

  return order;
}

File Upload with Validation

js
async function uploadDocument(fileData, metadata) {
  // Validate file type
  const allowedTypes = ['application/pdf', 'image/jpeg', 'image/png'];
  if (!allowedTypes.includes(fileData.contentType)) {
    throw new Error('Invalid file type');
  }

  // Validate file size (5MB max)
  const maxSize = 5 * 1024 * 1024;
  if (fileData.size > maxSize) {
    throw new Error('File too large');
  }

  // Upload file
  const file = new Nimbu.File(fileData);
  await file.save();

  // Create document record
  const document = new Nimbu.Object('documents');
  document.set('title', metadata.title);
  document.set('description', metadata.description);
  document.set('file', file);
  document.set('uploaded_by', metadata.uploadedBy);

  await document.save();

  return {
    id: document.id,
    url: file.url()
  };
}

Best Practices

1. Use Specialized Classes When Available

js
// Good: Use specialized class
const customer = new Nimbu.Customer();

// Avoid: Generic object for specialized types
const customer = new Nimbu.Object('customers');

2. Include Relations to Avoid N+1 Queries

js
// Good: Include related data
const query = new Nimbu.Query('orders');
query.include('customer');
query.include('products');
const orders = await query.collection().fetch();

// Avoid: Fetching relations separately
const orders = await query.collection().fetch();
for (const order of orders) {
  const customer = await order.get('customer').fetch(); // N+1 query!
}

3. Validate Data Before Saving

js
// Good: Validate before save
if (!email || !email.includes('@')) {
  throw new Error('Invalid email');
}
await customer.save();

// Avoid: Saving without validation
await customer.save(); // May fail with unclear error

4. Handle Errors Gracefully

js
// Good: Error handling
try {
  await order.save();
} catch (error) {
  console.error('Failed to save order:', error.message);
  // Handle error appropriately
}

// Avoid: No error handling
await order.save(); // Unhandled errors

Next Steps