Syntax Sugar
This document shows how to use the safe and sqlSafe syntax sugar provided by the SDK to simplify error handling code.
Version Requirements
safefunction requires@lovrabet/sdkv1.3.0 or highersqlSafefunction requires@lovrabet/sdkv1.3.0 or higher
Traditional Approach: Verbose and Error-Prone
Scenario 1: Regular API Calls
// 📌 Traditional approach: Two-level nesting
try {
const users = await client.models.users.filter();
console.log(users);
} catch (error) {
if (error instanceof LovrabetError) {
console.error(error.message, error.description);
} else {
console.error(error);
}
}
Problems:
- try-catch adds nesting levels
- Manual error type checking required
- Large code volume, poor readability
Scenario 2: SQL Queries
// 📌 Traditional approach: Three-level checking
try {
const result = await client.sql.execute({ sqlCode: "xxx" });
// Business layer check
if (result.execSuccess && result.execResult) {
console.log(`Found ${result.execResult.length} records`);
result.execResult.forEach((row) => console.log(row));
} else {
console.error("SQL execution failed");
}
} catch (error) {
if (error instanceof LovrabetError) {
console.error("Request failed:", error.message);
}
}
Problems:
- HTTP errors + business logic errors, two-level checking
- Nested access to
execResult - Code duplication, easy to miss checks
Scenario 3: Concurrent Requests
// 📌 Traditional approach: Scattered error handling
const [users, orders, stats] = await Promise.all([
client.models.users.filter().catch((e) => ({ error: e })),
client.models.orders.filter().catch((e) => ({ error: e })),
client.sql.execute({ sqlCode: "stats" }).catch((e) => ({ error: e })),
]);
if (users.error) console.error("Failed to get users");
if (orders.error) console.error("Failed to get orders");
if (stats.error) {
console.error("Failed to get statistics");
} else {
if (!stats.data.execSuccess) {
console.error("SQL execution failed");
}
}
Problems:
- Each request needs separate error handling
- SQL business status checking is more complex
- Inconsistent code structure
Using safe: Simplify Regular API Error Handling
import { safe } from "@lovrabet/sdk";
// 💡 Syntax sugar: Single check
const { data, error } = await safe(() => client.models.users.filter());
if (error) {
console.error("Query failed:", error.message, error.description);
return;
}
// data is directly the result data
console.log(data);
Comparison:
| Traditional | safe |
|---|---|
| try-catch nesting | Flat destructuring |
| Manual error type checking | Automatically converts to LovrabetError |
| 5-10 lines of code | 3 lines of code |
Concurrent Requests: Unified Structure
// ✅ Concise: Unified handling
const [usersResult, ordersResult, statsResult] = await Promise.all([
safe(() => client.models.users.filter()),
safe(() => client.models.orders.filter()),
safe(() => client.sql.execute({ sqlCode: "stats" })),
]);
// Check individually
if (usersResult.error) console.error("Users failed");
if (ordersResult.error) console.error("Orders failed");
if (statsResult.error) console.error("Stats failed");
// Use successful data
usersResult.data?.forEach((user) => console.log(user));
Using sqlSafe: Optimized for SQL
import { sqlSafe } from "@lovrabet/sdk";
// ✅ Concise: Single check, directly get array
const { data, error } = await sqlSafe(() =>
client.sql.execute({ sqlCode: "user-stats" })
);
if (!error) {
// data is directly the query result array
console.log(`Found ${data.length} records`);
data.forEach((row) => console.log(row));
}
Comparison:
| Traditional | sqlSafe |
|---|---|
| try-catch + execSuccess check | Single if check |
| Access result.execResult | Direct data access |
| 10-15 lines of code | 5 lines of code |
Typed SQL Queries
interface UserStat {
id: number;
name: string;
login_count: number;
}
const { data, error } = await sqlSafe<UserStat>(() =>
client.sql.execute<UserStat>({ sqlCode: "user-stats" })
);
if (error) return;
// data is UserStat[], type-safe
data.forEach((stat) => {
console.log(`${stat.name}: ${stat.login_count} logins`);
});
Syntax Sugar Comparison Table
| Scenario | Traditional (Lines of Code) | Syntax Sugar (Lines of Code) |
|---|---|---|
| Regular API error handling | 8-10 lines | 3 lines |
| Complete SQL query handling | 15-20 lines | 5 lines |
| Concurrent requests | 30+ lines | 10 lines |
| Type-safe access | Requires type assertions | Auto-inferred |
Best Practices
1. Prefer Syntax Sugar
// 💡 Syntax sugar: Concise
const { data, error } = await safe(() => api.call());
if (error) return;
// 📌 Traditional: Verbose
try {
const data = await api.call();
} catch (e) {
if (e instanceof LovrabetError) {
// ...
}
}
2. SQL Must Use sqlSafe
// 💡 Syntax sugar: Single check
const { data, error } = await sqlSafe(() => client.sql.execute(...));
// ❌ Avoid: Easy to miss business checks
const result = await client.sql.execute(...);
result.execResult?.forEach(...); // May have execSuccess=false
3. Early Return Pattern
const fetchUsers = async () => {
const { data, error } = await safe(() => client.models.users.filter());
if (error) return { success: false, error: error.message };
return { success: true, data };
};
4. Unified Concurrent Request Handling
const loadDashboard = async () => {
const [users, orders, stats] = await Promise.all([
sqlSafe(() => client.sql.execute({ sqlCode: "users" })),
sqlSafe(() => client.sql.execute({ sqlCode: "orders" })),
sqlSafe(() => client.sql.execute({ sqlCode: "stats" })),
]);
if (users.error || orders.error || stats.error) {
console.error("Data loading failed");
return;
}
return {
users: users.data!,
orders: orders.data!,
stats: stats.data!,
};
};
API Reference
safe
function safe<T>(fn: Promise<T> | (() => Promise<T>)): Promise<SafeResult<T>>;
interface SafeResult<T> {
data: T | null;
error: LovrabetError | null;
}
sqlSafe
function sqlSafe<T>(
fn: Promise<SqlExecuteResult<T>> | (() => Promise<SqlExecuteResult<T>>)
): Promise<SqlSafeResult<T>>;
interface SqlSafeResult<T> {
data: T[] | null;
error: LovrabetError | null;
}
Related Documentation
- Error Handling Guide - Detailed error handling mechanisms
- SQL API Reference - SQL API detailed documentation
- API Reference Manual - Complete API documentation