Build a Complete CRUD Application with Symulate BYOK and Your OpenAI API Key
Want to build a working CRUD application with realistic, AI-generated data without paying for yet another SaaS platform? Symulate SDK is now fully open source (MIT License), and you can use it completely free with just your own OpenAI API key.
In this tutorial, we'll build a complete e-commerce product management system with:
- β Full CRUD operations (Create, Read, Update, Delete)
- β AI-generated realistic product data
- β Local persistence (works offline after initial generation)
- β Flexible response schemas with aggregates
- β Type-safe TypeScript throughout
- β Total cost: ~$0.01-0.05 per development session
Why BYOK (Bring Your Own Key)?
Before we dive in, let's understand the benefits:
What you get:
- Complete SDK functionality - no limitations
- AI-realistic data generation
- Local persistence (localStorage in browser, filesystem in Node.js)
- Zero vendor lock-in
- Open source MIT license
What you pay:
- Only OpenAI API costs (~$0.001 per generation with gpt-4o-mini)
- Essentially free for development and prototyping
What you don't get:
- Cloud hosting (you use local persistence instead)
- Branch isolation for multi-tenant demos
- Team collaboration features
For individual developers, startups, and learning projects, BYOK is perfect.
Prerequisites
Before we start, you'll need:
- Node.js 18+ installed
- An OpenAI API key - Get one free at platform.openai.com/api-keys
- Basic TypeScript knowledge
Step 1: Project Setup
Let's create a new project and install Symulate SDK:
# Create new project
mkdir symulate-product-manager
cd symulate-product-manager
npm init -y
# Install Symulate SDK
npm install @symulate/sdk
# Install TypeScript and dev dependencies
npm install -D typescript @types/node tsx
# Initialize TypeScript
npx tsc --init
Create a .env file for your OpenAI API key:
# .env
OPENAI_API_KEY=sk-your-key-here
Important: Add .env to your .gitignore to keep your API key secure!
Step 2: Configure Symulate with BYOK
Create src/config.ts:
import { configureSymulate } from '@symulate/sdk';
// Configure Symulate with your OpenAI API key
configureSymulate({
openaiApiKey: process.env.OPENAI_API_KEY,
generateMode: 'ai', // Use AI generation
environment: 'development',
// persistence automatically defaults to "local" for BYOK!
// Data will be saved to .symulate-product-manager.json
});
console.log('β
Symulate configured with BYOK mode');
That's it! No platform account needed. The SDK automatically uses local filesystem persistence when you're in BYOK mode.
Step 3: Define Your Product Schema
Create src/schema.ts:
import { m, type Infer } from '@symulate/sdk';
// Define a rich product schema
export const ProductSchema = m.object({
id: m.uuid(),
name: m.string(),
description: m.string(),
price: m.number({ min: 10, max: 2000 }),
category: m.string(),
brand: m.string(),
inStock: m.boolean(),
rating: m.number({ min: 1, max: 5 }),
reviewCount: m.number({ min: 0, max: 1000 }),
imageUrl: m.internet.url(),
tags: m.array(m.string(), { min: 2, max: 5 }),
sku: m.string(),
weight: m.number({ min: 0.1, max: 50 }),
dimensions: m.object({
length: m.number(),
width: m.number(),
height: m.number(),
}),
});
// Infer TypeScript type from schema
export type Product = Infer<typeof ProductSchema>;
The schema defines the structure of our product data. The AI will use this to generate realistic products.
Step 4: Create the Products Collection
Create src/products.ts:
import { defineCollection } from '@symulate/sdk';
import { ProductSchema, type Product } from './schema';
// Define collection with AI-powered seed data
export const products = defineCollection<Product>({
name: 'products',
basePath: '/api/products',
schema: ProductSchema,
seedCount: 25, // Generate 25 products initially
seedInstruction: `Generate realistic e-commerce products with these characteristics:
- Categories: Electronics, Clothing, Home & Garden, Sports, Books, Beauty
- Mix of well-known brands (Apple, Nike, Samsung, etc.) and fictional brands
- Prices should be realistic for each category
- 80% products in stock, 20% out of stock
- Ratings mostly between 3-5 stars with realistic distribution
- Diverse product types within each category
- Professional product descriptions
- Realistic SKU patterns (e.g., ELEC-APL-001)
`,
operations: {
// Enable all CRUD operations with custom response schemas
list: {
responseSchema: m.object({
data: m.array(ProductSchema),
pagination: m.object({
page: m.collectionsMeta.page(),
limit: m.collectionsMeta.limit(),
total: m.collectionsMeta.total(),
totalPages: m.collectionsMeta.totalPages(),
}),
stats: m.object({
averagePrice: m.collectionsMeta.avg('price'),
totalValue: m.collectionsMeta.sum('price'),
minPrice: m.collectionsMeta.min('price'),
maxPrice: m.collectionsMeta.max('price'),
inStockCount: m.collectionsMeta.count('inStock', true),
outOfStockCount: m.collectionsMeta.count('inStock', false),
}),
}),
mock: {
delay: 300, // Simulate 300ms network latency
},
},
get: {
mock: { delay: 200 },
},
create: {
mock: { delay: 400 },
},
update: {
mock: { delay: 350 },
},
delete: {
mock: { delay: 250 },
},
},
});
Notice the responseSchema - this gives us a flexible response with pagination, the actual data, AND computed statistics (average price, stock counts, etc.). This is all calculated automatically!
Step 5: Build the Application
Now let's create a complete CRUD interface. Create src/index.ts:
import './config'; // Initialize configuration
import { products } from './products';
import type { Product } from './schema';
// Helper to display product info
function displayProduct(product: Product): void {
console.log(`
π¦ ${product.name}
Brand: ${product.brand}
Category: ${product.category}
Price: $${product.price.toFixed(2)}
Rating: ${product.rating}β (${product.reviewCount} reviews)
Stock: ${product.inStock ? 'β
In Stock' : 'β Out of Stock'}
SKU: ${product.sku}
Tags: ${product.tags.join(', ')}
`);
}
async function main() {
console.log('\nπ Starting Product Manager with Symulate BYOK\n');
try {
// 1. LIST ALL PRODUCTS with statistics
console.log('π Listing all products...\n');
const listResult = await products.list({
page: 1,
limit: 5,
sortBy: 'price',
sortOrder: 'desc',
});
console.log(`Found ${listResult.pagination.total} products (showing first ${listResult.data.length}):`);
listResult.data.forEach(displayProduct);
console.log('\nπ Store Statistics:');
console.log(` Average Price: $${listResult.stats.averagePrice.toFixed(2)}`);
console.log(` Price Range: $${listResult.stats.minPrice} - $${listResult.stats.maxPrice}`);
console.log(` Total Inventory Value: $${listResult.stats.totalValue.toFixed(2)}`);
console.log(` In Stock: ${listResult.stats.inStockCount} products`);
console.log(` Out of Stock: ${listResult.stats.outOfStockCount} products`);
// 2. GET A SINGLE PRODUCT
const firstProductId = listResult.data[0].id;
console.log(`\nπ Getting details for product: ${firstProductId}`);
const singleProduct = await products.get(firstProductId);
if (singleProduct) {
displayProduct(singleProduct);
console.log(` Description: ${singleProduct.description}`);
console.log(` Dimensions: ${singleProduct.dimensions.length}x${singleProduct.dimensions.width}x${singleProduct.dimensions.height} cm`);
console.log(` Weight: ${singleProduct.weight} kg`);
}
// 3. CREATE A NEW PRODUCT
console.log('\nβ Creating a new product...');
const newProduct = await products.create({
name: 'Custom Gaming Laptop Pro',
description: 'High-performance gaming laptop with RTX 4080, 32GB RAM, and 1TB NVMe SSD',
price: 2499.99,
category: 'Electronics',
brand: 'TechPro Gaming',
inStock: true,
rating: 4.8,
reviewCount: 0,
imageUrl: 'https://example.com/gaming-laptop.jpg',
tags: ['gaming', 'laptop', 'high-performance', 'RTX'],
sku: 'ELEC-TPG-LAPTOP-001',
weight: 2.5,
dimensions: {
length: 35,
width: 25,
height: 2.5,
},
});
console.log('β
Product created successfully!');
displayProduct(newProduct);
// 4. UPDATE THE PRODUCT
console.log('\nβοΈ Updating product price (Black Friday sale!)...');
const updated = await products.update(newProduct.id, {
price: 1999.99,
reviewCount: 15,
});
if (updated) {
console.log('β
Product updated successfully!');
console.log(` New price: $${updated.price} (was $${newProduct.price})`);
console.log(` New review count: ${updated.reviewCount}`);
}
// 5. FILTER PRODUCTS
console.log('\nπ Finding all Electronics under $500...');
const filtered = await products.list({
filter: {
category: 'Electronics',
price: { $lt: 500 },
inStock: true,
},
limit: 3,
});
console.log(`Found ${filtered.data.length} matching products:`);
filtered.data.forEach(displayProduct);
// 6. DELETE THE PRODUCT
console.log(`\nποΈ Deleting test product (${newProduct.id})...`);
const deleted = await products.delete(newProduct.id);
console.log(deleted ? 'β
Product deleted successfully!' : 'β Failed to delete product');
// 7. FINAL STATS
console.log('\nπ Final Statistics:');
const finalList = await products.list({ limit: 1 });
console.log(` Total products: ${finalList.pagination.total}`);
console.log(` Average price: $${finalList.stats.averagePrice.toFixed(2)}`);
console.log(` In stock: ${finalList.stats.inStockCount}`);
console.log('\nβ
Demo completed successfully!');
console.log('\nπΎ Data persisted to: .symulate-product-manager.json');
console.log('π Run this again to see data loaded from persistence!');
console.log('π° OpenAI API cost for initial generation: ~$0.02');
} catch (error: any) {
console.error('β Error:', error.message);
process.exit(1);
}
}
// Run the application
main();
Step 6: Run Your Application
Add a script to package.json:
{
"scripts": {
"start": "tsx src/index.ts"
}
}
Now run it:
npm start
On first run:
- The SDK connects to OpenAI and generates 25 realistic products (~$0.02 cost)
- Data is saved to
.symulate-product-manager.json - You'll see all CRUD operations execute with simulated delays
On subsequent runs:
- Data loads instantly from the local file (FREE!)
- No OpenAI API calls unless you clear the file
- Full offline development capability
What Just Happened?
Let's break down the magic:
1. AI-Generated Realistic Data
The seedInstruction told the AI exactly what kind of products to generate. Instead of getting "Product 1", "Product 2", you get realistic products like:
- "Apple MacBook Pro 16-inch M3 Max"
- "Nike Air Zoom Pegasus 40 Running Shoes"
- "Samsung 55-inch QLED Smart TV"
Each with realistic prices, descriptions, ratings, and metadata.
2. Local Persistence (Automatic)
When using BYOK mode, Symulate automatically saves all data locally:
- Browser: Uses
localStorage - Node.js: Uses filesystem (JSON file)
This means after the initial AI generation, everything works offline and costs nothing.
3. Flexible Response Schemas
The responseSchema lets you customize the API response structure:
{
data: [...products...],
pagination: { page: 1, limit: 5, total: 25, totalPages: 5 },
stats: {
averagePrice: 245.67,
totalValue: 6141.75,
minPrice: 12.99,
maxPrice: 1299.99,
inStockCount: 20,
outOfStockCount: 5
}
}
All these statistics are calculated automatically from your data. No manual computation needed!
4. Type Safety Throughout
TypeScript knows the exact shape of your data:
const result = await products.list();
result.data[0].price // β
TypeScript knows this is a number
result.stats.averagePrice // β
TypeScript knows this exists
result.randomField // β TypeScript error - field doesn't exist
5. Delay Simulation
The mock: { delay: 300 } config simulates real network latency. This helps you test:
- Loading states in your UI
- Race conditions
- User experience with slow connections
Advanced Features
Filtering with Operators
const products = await products.list({
filter: {
price: { $gte: 100, $lte: 500 }, // Between $100 and $500
category: { $in: ['Electronics', 'Books'] }, // Multiple categories
inStock: true,
rating: { $gt: 4.0 }, // 4+ stars only
}
});
Sorting
const products = await products.list({
sortBy: 'price',
sortOrder: 'desc', // Highest price first
});
Pagination
const page1 = await products.list({ page: 1, limit: 10 });
const page2 = await products.list({ page: 2, limit: 10 });
Replace vs Update
// Update: Partial update, other fields preserved
await products.update(id, { price: 99.99 });
// Replace: Full replacement, unspecified fields removed
await products.replace(id, completeNewProductObject);
Cost Breakdown
Let's talk about actual costs:
Initial Setup:
- 25 products with detailed schemas: ~$0.015-0.025
- Runs once, then cached locally
Ongoing Development:
- FREE! Data loads from local persistence
- Only regenerate if you clear the cache or want new data
Comparison:
- Traditional SaaS mock API: $10-50/month
- Symulate BYOK: ~$0.05/month (occasional regenerations)
- Savings: ~99% cost reduction
When to Upgrade to Symulate Platform
BYOK is perfect for most individual developers, but consider upgrading to Symulate Platform if you need:
- Cloud Persistence - Share data across your team
- Isolated Demos - Different data per git branch (perfect for agencies)
- Team Collaboration - Multiple developers working on shared mock data
- Priority Support - Get help from our team when you need it
You can start with BYOK and upgrade anytime. Your code doesn't change - just the configuration.
Complete Source Code
The complete working example is available in the Symulate SDK repository:
Next Steps
Now that you have a working CRUD application:
- Add More Collections - Create users, orders, reviews
- Build a Frontend - Connect React, Vue, or Angular
- Add Error Simulation - Test error handling:
operations: { create: { errors: [ { code: 400, failIf: (data) => !data.name, description: 'Product name is required' } ] } } - Explore Custom Response Schemas - Shape responses exactly how you need them
Conclusion
With Symulate BYOK, you get:
- β Professional mock data - AI-generated, contextually perfect
- β Full CRUD operations - Production-ready API interface
- β Local development - Works offline after initial setup
- β Type-safe - Full TypeScript support
- β Minimal cost - ~$0.05/month for development
- β No vendor lock-in - It's your data, your infrastructure
All with just your OpenAI API key and 10 minutes of setup time.
Ready to build something amazing? Install Symulate SDK and get started:
npm install @symulate/sdk
Check out our Open Source documentation for more examples and guides.
Happy coding! π
Ready to try Symulate?
Start building frontends without waiting for backend APIs. Get 100K free AI tokens.
Sign Up Free