Frontend SDK
The @dynamia-tools/sdk is the official JavaScript and TypeScript client library for Dynamia Platform. It provides a clean, fully-typed interface to interact with your backend’s REST APIs, making it easy to build modern web applications with React, Vue, Angular, or any other JavaScript framework.
Why Use the SDK?
Section titled “Why Use the SDK?”Instead of manually crafting fetch requests and managing API endpoints, the SDK gives you:
- 🎯 Full TypeScript Support – Autocomplete and type safety for all API calls
- 🚀 Zero Runtime Dependencies – Lightweight and fast
- 📦 Complete API Coverage – Access metadata, CRUD operations, actions, reports, files, and more
- 🔐 Flexible Authentication – Support for Bearer tokens, Basic Auth, and session cookies
- 🛡️ Built-in Error Handling – Clear error messages with proper types
Getting Started
Section titled “Getting Started”Installation
Section titled “Installation”Install the package using your favorite package manager:
# pnpm (recommended)pnpm add @dynamia-tools/sdk
# npmnpm install @dynamia-tools/sdk
# yarnyarn add @dynamia-tools/sdkBasic Usage
Section titled “Basic Usage”Create a client instance and start making API calls:
import { DynamiaClient } from '@dynamia-tools/sdk';
// Initialize the clientconst client = new DynamiaClient({ baseUrl: 'https://your-app.example.com', token: 'your-jwt-token-here',});
// Fetch application metadataconst app = await client.metadata.getApp();console.log(`Connected to ${app.name} v${app.version}`);
// Work with entitiesconst books = await client.crud('store/books').findAll();console.log(`Found ${books.total} books`);Authentication
Section titled “Authentication”The SDK supports multiple authentication methods to fit your application’s needs:
Bearer Token (Recommended for SPAs)
Section titled “Bearer Token (Recommended for SPAs)”Perfect for single-page applications using JWT tokens:
const client = new DynamiaClient({ baseUrl: 'https://api.example.com', token: 'eyJhbGciOiJIUzI1NiJ9...',});Basic Authentication
Section titled “Basic Authentication”For server-to-server communication:
const client = new DynamiaClient({ baseUrl: 'https://api.example.com', username: 'admin', password: 'secret',});Session-Based (with Cookies)
Section titled “Session-Based (with Cookies)”For traditional web applications using session cookies:
const client = new DynamiaClient({ baseUrl: 'https://api.example.com', withCredentials: true, // Include cookies in requests});Core Features
Section titled “Core Features”📋 Working with Entities (CRUD)
Section titled “📋 Working with Entities (CRUD)”The CRUD API makes it simple to manage your domain entities:
// Get a reference to an entity collectionconst books = client.crud('catalog/books');
// List all books with paginationconst page = await books.findAll({ page: 1, size: 20 });
// Search and filterconst results = await books.findAll({ q: 'typescript', author: 'Martin Fowler'});
// Get a single book by IDconst book = await books.findById(42);
// Create a new bookconst newBook = await books.create({ title: 'Clean Code', author: 'Robert C. Martin', isbn: '978-0132350884',});
// Update an existing bookconst updated = await books.update(42, { price: 49.99,});
// Delete a bookawait books.delete(42);🎯 Executing Actions
Section titled “🎯 Executing Actions”Trigger business logic and server-side actions:
// Execute a global actionconst result = await client.actions.executeGlobal('sendWelcomeEmail', { params: { userId: 123 },});
// Execute an entity-specific actionconst orderResult = await client.actions.executeEntity( 'com.example.domain.Order', 'approveOrder', { data: { orderId: 99 }, params: { notify: true } });
console.log(orderResult.message); // "Order approved successfully"🗂️ Application Metadata
Section titled “🗂️ Application Metadata”Discover your application’s structure at runtime:
// Get application infoconst app = await client.metadata.getApp();
// Get the full navigation treeconst nav = await client.metadata.getNavigation();
// Build a dynamic menunav.modules.forEach(module => { console.log(`📦 ${module.name}`); module.groups.forEach(group => { group.pages.forEach(page => { console.log(` → ${page.name} (${page.virtualPath})`); }); });});
// Get metadata for a specific entityconst bookMeta = await client.metadata.getEntity('com.example.domain.Book');
// Get view descriptors (form, table, etc.)const formDescriptor = await client.metadata.getEntityView( 'com.example.domain.Book', 'form');📊 Reports
Section titled “📊 Reports”Access and generate reports from your backend:
// List all available reportsconst reports = await client.reports.list();
// Fetch report data with filtersconst salesData = await client.reports.get('sales', 'monthly-summary', { year: '2026', month: '03',});
// Or use POST for complex filtersconst data = await client.reports.post('sales', 'monthly-summary', { filters: [ { name: 'year', value: '2026' }, { name: 'status', value: 'CLOSED' }, ],});📁 File Management
Section titled “📁 File Management”Download and manage files from the entity-files extension:
// Download a file as a Blobconst blob = await client.files.download('invoice.pdf', 'uuid-123');
// Or get a direct URL for imagesconst imageUrl = client.files.getUrl('profile-pic.jpg', 'uuid-456');
// Use in your HTML<img src={imageUrl} alt="Profile" />🏢 Multi-Tenancy (SaaS)
Section titled “🏢 Multi-Tenancy (SaaS)”Manage tenant accounts in multi-tenant applications:
// Get account informationconst account = await client.saas.getAccount('account-uuid');
console.log(`Account: ${account.name}`);console.log(`Status: ${account.status}`);console.log(`Subdomain: ${account.subdomain}`);Error Handling
Section titled “Error Handling”The SDK throws typed errors that are easy to catch and handle:
import { DynamiaApiError } from '@dynamia-tools/sdk';
try { const book = await client.crud('books').findById(9999);} catch (error) { if (error instanceof DynamiaApiError) { console.error(`API Error [${error.status}]: ${error.message}`);
// Handle specific status codes if (error.status === 404) { console.log('Book not found'); } else if (error.status === 401) { console.log('Unauthorized - please login'); } } else { console.error('Unexpected error:', error); }}TypeScript Support
Section titled “TypeScript Support”The SDK is written in TypeScript and provides full type definitions for all APIs:
import type { ApplicationMetadata, NavigationTree, EntityMetadata, ViewDescriptor, ActionExecutionResponse, CrudListResult,} from '@dynamia-tools/sdk';
// Generic CRUD operations with custom typesinterface Book { id: number; title: string; author: string; isbn: string; price: number;}
const books = client.crud<Book>('catalog/books');const result: CrudListResult<Book> = await books.findAll();
result.content.forEach(book => { // ✅ Full autocomplete and type checking console.log(`${book.title} by ${book.author} - $${book.price}`);});Real-World Example
Section titled “Real-World Example”Here’s a complete example of building a book management feature:
import { DynamiaClient } from '@dynamia-tools/sdk';
// Initialize clientconst client = new DynamiaClient({ baseUrl: import.meta.env.VITE_API_URL, token: localStorage.getItem('auth_token'),});
// Define your entity typeinterface Book { id?: number; title: string; author: string; isbn: string; price: number; publishedDate: string;}
// Create a book manager classclass BookManager { private crud = client.crud<Book>('store/catalog/books');
async searchBooks(query: string) { return await this.crud.findAll({ q: query, page: 1, size: 10 }); }
async getBook(id: number) { return await this.crud.findById(id); }
async createBook(book: Omit<Book, 'id'>) { return await this.crud.create(book); }
async updateBook(id: number, updates: Partial<Book>) { return await this.crud.update(id, updates); }
async deleteBook(id: number) { await this.crud.delete(id); }
async exportBooks() { const result = await client.actions.executeGlobal('exportBooksToExcel', { params: { format: 'xlsx' } }); return result.data; }}
// Use it in your appconst bookManager = new BookManager();
// Searchconst results = await bookManager.searchBooks('clean code');console.log(`Found ${results.total} books`);
// Createconst newBook = await bookManager.createBook({ title: 'The Pragmatic Programmer', author: 'Andrew Hunt', isbn: '978-0135957059', price: 44.95, publishedDate: '2019-09-13',});
// Updateawait bookManager.updateBook(newBook.id!, { price: 39.99 });
// Exportawait bookManager.exportBooks();Advanced Configuration
Section titled “Advanced Configuration”Custom Fetch Implementation
Section titled “Custom Fetch Implementation”You can provide your own fetch implementation (useful for Node.js or testing):
import fetch from 'node-fetch';
const client = new DynamiaClient({ baseUrl: 'https://api.example.com', token: 'token', fetch: fetch as any,});Request Interceptors
Section titled “Request Interceptors”While the SDK doesn’t include built-in interceptors, you can wrap the client methods:
class TrackedDynamiaClient extends DynamiaClient { async request(endpoint: string, init?: RequestInit) { console.log(`[API] ${init?.method || 'GET'} ${endpoint}`); const start = Date.now();
try { const response = await super.request(endpoint, init); console.log(`[API] Completed in ${Date.now() - start}ms`); return response; } catch (error) { console.error(`[API] Failed after ${Date.now() - start}ms`, error); throw error; } }}Best Practices
Section titled “Best Practices”1. Reuse Client Instances
Section titled “1. Reuse Client Instances”Create one client instance and reuse it throughout your application:
export const apiClient = new DynamiaClient({ baseUrl: import.meta.env.VITE_API_URL, token: () => localStorage.getItem('auth_token'), // Lazy evaluation});2. Handle Token Refresh
Section titled “2. Handle Token Refresh”Implement token refresh logic in your authentication layer:
async function refreshToken() { const newToken = await fetch('/auth/refresh').then(r => r.json()); localStorage.setItem('auth_token', newToken.token);
// Create new client with updated token return new DynamiaClient({ baseUrl: API_URL, token: newToken.token, });}3. Type Your Entities
Section titled “3. Type Your Entities”Always define TypeScript interfaces for your domain entities:
export interface Book { id: number; title: string; author: string; // ... other fields}
// Use throughout your appconst books = client.crud<Book>('books');4. Centralize Error Handling
Section titled “4. Centralize Error Handling”Create a wrapper for consistent error handling:
async function safeApiCall<T>( operation: () => Promise<T>, fallback?: T): Promise<T | undefined> { try { return await operation(); } catch (error) { if (error instanceof DynamiaApiError) { notifyUser(`Error: ${error.message}`); } return fallback; }}
// Usageconst books = await safeApiCall( () => client.crud('books').findAll(), { content: [], total: 0, page: 1, pageSize: 20 });Framework Integration Examples
Section titled “Framework Integration Examples”import { useState, useEffect } from 'react';import { apiClient } from './api-client';
function BookList() { const [books, setBooks] = useState([]); const [loading, setLoading] = useState(true);
useEffect(() => { apiClient.crud('books').findAll() .then(result => setBooks(result.content)) .finally(() => setLoading(false)); }, []);
if (loading) return <div>Loading...</div>;
return ( <ul> {books.map(book => ( <li key={book.id}>{book.title}</li> ))} </ul> );}<script setup lang="ts">import { ref, onMounted } from 'vue';import { apiClient } from './api-client';
const books = ref([]);const loading = ref(true);
onMounted(async () => { const result = await apiClient.crud('books').findAll(); books.value = result.content; loading.value = false;});</script>
<template> <div v-if="loading">Loading...</div> <ul v-else> <li v-for="book in books" :key="book.id"> {{ book.title }} </li> </ul></template>Svelte
Section titled “Svelte”<script lang="ts"> import { onMount } from 'svelte'; import { apiClient } from './api-client';
let books = []; let loading = true;
onMount(async () => { const result = await apiClient.crud('books').findAll(); books = result.content; loading = false; });</script>
{#if loading} <div>Loading...</div>{:else} <ul> {#each books as book (book.id)} <li>{book.title}</li> {/each} </ul>{/if}Next Steps
Section titled “Next Steps”- Check out the complete API reference in the repository
- Explore the demo applications for more examples
- Join our community Discord for support and discussions
Contributing
Section titled “Contributing”We welcome contributions! Please see our Contributing Guide for details.
License
Section titled “License”Apache License 2.0 - see LICENSE for details.