New App Template
This guide covers initialization patterns and templates for creating new Farseer applications.
Initialization Patterns
Auto-Configuration (Recommended for Production)
When running inside a Farseer environment, the client auto-configures from environment variables:
import { FarseerClient } from 'farseer-client';
const client = new FarseerClient();
Required environment variables:
| Variable | Description |
|---|---|
TENANT_ID | Your Farseer tenant identifier |
FARSEER_API_KEY | API authentication key |
FARSEER_URL | Base URL (e.g., https://app.farseer.io) |
Manual Configuration (Development)
const client = new FarseerClient({
basePath: 'https://app.farseer.io/api/v3',
headers: {
'X-TENANT-ID': 'my-tenant-id',
'X-API-KEY': 'my-api-key',
},
});
Recommended: Dev/Prod Pattern
tip
Always implement local initialization for testing before deploying to production. This prevents accidental data modifications during development.
import * as farseer from 'farseer-client';
// Environment detection
const CFG_DEV_ENV =
process.env.FARSEER_URL === undefined &&
process.env.FARSEER_API_KEY === undefined;
// Development credentials
const DEV_TENANT_ID = 'your-tenant-dev';
const DEV_API_KEY = 'your_dev_api_key_here';
const DEV_FARSEER_URL = 'https://your-tenant-dev.farseer.io/api/v3';
async function main() {
let client: farseer.FarseerClient;
if (CFG_DEV_ENV) {
console.log('Running in DEVELOPMENT mode');
console.log(` Tenant: ${DEV_TENANT_ID}`);
console.log(` URL: ${DEV_FARSEER_URL}`);
client = new farseer.FarseerClient(DEV_TENANT_ID, DEV_API_KEY, DEV_FARSEER_URL);
} else {
console.log('Running in PRODUCTION mode (using environment variables)');
client = new farseer.FarseerClient();
}
// Your application logic here...
}
main().catch(farseer.handleUnknownError);
Why this pattern?
- Safety - Test all logic against a development instance first
- Visibility - Console logs make it obvious which environment you're targeting
- Easy switching - Just set environment variables for production
- No code changes - Same code runs in both environments
Project Structure
your-app/
├── index.ts # Entry point with command routing
├── operations/
│ ├── syncSales.ts # Operation implementation
│ └── syncProducts.ts # Operation implementation
├── tagIds.ts # Hardcoded Farseer IDs (optional)
├── util.ts # Helper functions (optional)
└── credentials.ts # External service credentials (optional)
Entry Point with Command Routing
import * as farseer from 'farseer-client';
enum SelectArgument {
SYNC_SALES = 'sync-sales',
SYNC_PRODUCTS = 'sync-products',
}
async function main() {
const args = process.argv.slice(2);
const command = args[0] as SelectArgument;
const client = CFG_DEV_ENV
? new farseer.FarseerClient(DEV_TENANT_ID, DEV_API_KEY, DEV_URL)
: new farseer.FarseerClient();
switch (command) {
case SelectArgument.SYNC_SALES:
await syncSales(client);
break;
case SelectArgument.SYNC_PRODUCTS:
await syncProducts(client);
break;
default:
console.log(`Unknown command: ${command}`);
console.log(`Available: ${Object.values(SelectArgument).join(', ')}`);
}
}
main().catch(farseer.handleUnknownError);
Tag IDs File (Optional)
For apps that need hardcoded IDs:
export const TAG_IDS = {
DIMENSION_TABLES: {
PRODUCTS: 123,
YEARS: 124,
MONTHS: 125,
},
VARIABLES: {
REVENUE: 200,
COSTS: 201,
},
VERSIONS: {
ACTUAL: 26,
PLAN: 27,
},
};
Error Handling
Standard pattern:
main().catch(farseer.handleUnknownError);
Custom error handling:
main().catch(async (error: any) => {
if (error && typeof error.text === 'function') {
console.error(await error.text());
} else {
console.error(error);
}
process.exit(1);
});
Checklist for New Apps
- Create project folder
- Set up
index.tswith dev/prod initialization pattern - Create
tagIds.tswith Farseer dimension/variable IDs (if needed) - Implement operations in separate files
- Test in development mode first
- Verify imports work correctly before deploying