Dare: Database and REST API Generator
Dare is a JavaScript library (shipping TypeScript types) designed to streamline the creation of REST APIs from database schemas by generating SQL queries from structured JavaScript objects. It acts as an abstraction layer, allowing developers to define database interactions using a declarative object syntax rather than writing raw SQL directly. The current stable version is `0.98.4`, indicating it is still in pre-1.0 development, though it sees consistent maintenance with several bug fix and feature releases throughout 2025. Key differentiators include its 'brave API' approach to SQL generation, requiring users to define a custom `dare.execute` handler for database interaction, and its explicit support for MySQL (5.6, 5.7, 8.0) and PostgreSQL (16+), abstracting away direct driver calls.
Common errors
-
TypeError: this.execute is not a function
cause `dare.execute` handler was not defined or assigned correctly after `Dare` instantiation.fixAssign an asynchronous function to `dare.execute` that takes a `request` object and performs database operations. Example: `dare.execute = async (request) => { /* ... */ };` -
Error: SQLSTATE[HY000]: General error: 1064 You have an error in your SQL syntax...
cause The generated SQL from Dare's methods (e.g., `get`, `post`) resulted in invalid syntax for the configured database engine, or an underlying database driver issue occurred.fixEnable logging for `request.sql` and `request.values` within `dare.execute` to inspect the generated query. Verify your `engine` option in the `Dare` constructor matches your database. Check the Dare documentation for complex query patterns or filters. -
SyntaxError: Cannot use import statement outside a module
cause Attempting to use `import Dare from 'dare';` in a CommonJS (CJS) environment without proper configuration or transpilation.fixEnsure your Node.js project is configured for ESM by setting `"type": "module"` in `package.json`, or explicitly use CommonJS `require()` syntax if supported, though `dare` is primarily designed for ESM. For Node.js versions requiring `--experimental-modules`, ensure that flag is used. -
Error: The 'engine' option is missing or invalid. Supported engines: 'mysql:X', 'postgres:X'
cause The `engine` property was not provided or had an incorrect format during `Dare` instantiation.fixPass a valid `engine` string to the `Dare` constructor, e.g., `new Dare({ engine: 'mysql:8.0' })` or `new Dare({ engine: 'postgres:16' })`.
Warnings
- breaking Dare now requires Node.js version 20 or higher. Applications running on older Node.js versions will fail to install or run the package.
- gotcha The `dare.execute` handler is mandatory and must be explicitly defined by the user. If not defined, Dare operations will throw an error indicating that `dare.execute` is not a function.
- gotcha Careful handling of `request.sql` vs. `request.text` is crucial within the `dare.execute` handler, especially when switching between MySQL/MariaDB and PostgreSQL. MySQL uses `request.sql`, while PostgreSQL's `pg` driver typically expects `request.text`.
- gotcha The library's versioning (`0.x.x`) indicates that it is still pre-1.0. While the project is actively maintained, users should be aware that minor version updates (e.g., 0.97.x to 0.98.x) could introduce breaking changes or significant behavioral shifts without strict adherence to semantic versioning for major releases.
Install
-
npm install dare -
yarn add dare -
pnpm add dare
Imports
- Dare
const Dare = require('dare');import Dare from 'dare';
- RequestOptions
import type { RequestOptions } from 'dare'; - DareInstance
import type { DareInstance } from 'dare';
Quickstart
import Dare from 'dare';
import mysql from 'mysql2/promise'; // or 'pg' for PostgreSQL
// Configure your database connection
const dbconn = mysql.createPool({
host: process.env.DB_HOST ?? 'localhost',
user: process.env.DB_USER ?? 'root',
password: process.env.DB_PASSWORD ?? '',
database: process.env.DB_NAME ?? 'testdb'
});
// Initiate Dare instance, specifying the database engine
const dare = new Dare({
engine: 'mysql:8.0' // or 'postgres:16'
});
// Define the handler for database requests
dare.execute = async (request) => {
console.log('Executing SQL:', request.sql, request.values);
const [rows] = await dbconn.query(request.sql, request.values);
// For DML operations, return an object with insertId/affectedRows
if (request.type !== 'select') {
return {
insertId: rows.insertId,
affectedRows: rows.affectedRows
};
}
return rows;
};
async function runExample() {
try {
// Make a request to get a user
const user = await dare.get('users', ['id', 'name', {emailAddress: 'email'}], {id: 1});
if (user) {
console.log(`User found: ${user.name} with email ${user.emailAddress}`);
} else {
console.log('User not found.');
}
// Example of an insert operation
const insertResult = await dare.post('users', {
name: 'Jane Doe',
email: 'jane.doe@example.com'
});
console.log(`Inserted user with ID: ${insertResult.insertId}`);
} catch (error) {
console.error('Dare operation failed:', error.message);
} finally {
await dbconn.end(); // Close the database connection pool
}
}
runExample();