Coral is a lightweight Node.js framework designed to dynamically generate RESTful API routes for Express applications using Mongoose models. It eliminates boilerplate code by automatically creating CRUD routes with built-in support for pagination, sorting, filtering, and nested sub-documents.
- ⚡ Auto-generated CRUD: Instantly create GET, POST, PUT, and DELETE routes.
- 🔍 Powerful Queries: Built-in support for
skip,limit,sort, andordervia query parameters. - 📂 Sub-document Support: Easily manage nested Mongoose documents.
- 🛡️ Middleware Support: Inject custom Express middlewares into your routes.
- 🔗 Reference Updates: Automatically update references in related models (via
updateRef). - 🛠️ Configurable: Fine-tune available methods, pagination limits, and more.
npm install coralCreating a full REST API for a "Product" model:
import express from 'express';
import mongoose from 'mongoose';
import Coral from 'coral';
const app = express();
app.use(express.json());
// 1. Define Mongoose Schema & Model
const ProductSchema = new mongoose.Schema({ name: String, price: Number });
const Product = mongoose.model('Product', ProductSchema);
// 2. Initialize Coral Router
const productRouter = Coral({
path: '/products',
model: Product
});
// 3. Use the generated router
app.use(productRouter);
app.listen(3000, () => console.log('Server running on port 3000'));The Coral constructor takes a configuration object. Here are the available options with examples for each:
| Property | Type | Description |
|---|---|---|
path |
string |
The base path for the routes. |
model |
Model |
The Mongoose model to bind to. |
methods |
string[] |
Allowed HTTP methods. Default: ['GET', 'POST', 'PUT', 'DELETE']. |
middlewares |
RequestHandler[] |
Custom Express middlewares to run before handlers. |
conditions |
QueryConditions |
Base Mongoose filter used for all operations. |
options |
QueryOptions |
Base Mongoose query options (sort, skip, limit, etc.). |
fields |
QueryFields |
Base field projection for query results. |
perPage |
number |
Default records per page for pagination. |
idAttribute |
string |
Custom field used for finding records by ID. Default: _id. |
idParam |
string |
URL param name used to read the route identifier (instead of idAttribute). |
query |
QueryDefaults |
Additional defaults merged with conditions, options, and fields. |
subDoc |
SubDocConfig |
Configuration for nested sub-documents. |
updateRef |
UpdateRefConfig |
Update a reference in a parent model on create. |
bodyFilter |
string[] |
Whitelist of request body keys to persist on create/update. |
Define the endpoint and the Mongoose model it interacts with.
Coral({
path: '/api/v1/users',
model: User
});If you want to create a read-only endpoint:
Coral({
path: '/products',
model: Product,
methods: ['GET'] // Only GET /products and GET /products/:id will be created
});Secure your routes with authentication or add logging:
const auth = (req, res, next) => {
if (req.headers.authorization === 'secret') return next();
res.status(401).send('Unauthorized');
};
Coral({
path: '/secure-data',
model: SecureModel,
middlewares: [auth]
});Control the default number of records returned for list requests:
Coral({
path: '/logs',
model: Log,
perPage: 50 // Default is 10
});Use a field other than _id for lookup (e.g., lookup by slug or email):
Coral({
path: '/profiles',
model: Profile,
idAttribute: 'username'
});
// Endpoint becomes: GET /profiles/:usernameManage embedded arrays in your Mongoose models:
// Model: { name: String, comments: [{ body: String }] }
Coral({
path: '/posts',
model: Post,
subDoc: {
path: 'comments',
idAttribute: '_id'
}
});
// Generates: POST /posts/:postId/comments, DELETE /posts/:postId/comments/:commentId, etc.Bind route params to a lookup field without using the default :idAttribute param name:
Coral({
path: '/profiles/:username',
model: Profile,
idAttribute: 'username',
idParam: 'username'
});Set base query behavior and then layer overrides in query:
Coral({
path: '/users',
model: User,
conditions: { active: true },
options: { sort: '-createdAt' },
fields: 'name email',
query: {
conditions: { role: { $in: ['admin', 'member'] } },
options: { limit: 20 },
fields: 'name email role'
}
});Only allow selected fields from the request payload:
Coral({
path: '/customers',
model: Customer,
bodyFilter: ['email', 'name']
});Automatically push the ID of a newly created record into a parent model's array:
Coral({
path: '/articles',
model: Article,
updateRef: {
model: User,
path: 'articles', // Array field in User model
findOneId: (req) => req.body.authorId // Find the user using this ID from request
}
});Coral supports the following query parameters for all GET list requests:
?limit=20- Limit results.?skip=10- Skip results.?page=2- Pagination (multiplies byperPage).?sort=createdAt&order=desc- Sorting (order can beasc,desc,1, or-1).?select=name,email- Field projection (translated to'name email').
A complete set of copy-paste examples is available in examples/.
It includes focused core-framework scenarios:
- Basic CRUD setup:
examples/basic-crud.js - Methods + middleware configuration:
examples/methods-and-middlewares.js - Custom
idAttributeandidParam:examples/custom-id-attribute-and-param.js - Query defaults (
conditions,options,fields,query):examples/query-defaults-and-overrides.js - Pagination (
perPage) and query overrides (sort,order,select):examples/pagination-and-limit-control.js - Request body filtering (
bodyFilter):examples/body-filter.js - Reference updates on create (
updateRef):examples/update-ref.js - Single-level and multi-level sub-document routing (
subDoc):examples/subdoc-single-level.js,examples/subdoc-multi-level.js
Here are a few tips to keep your data extra secure:
- Mass Assignment: Use Mongoose's
strictmode (default) andexpress-validatorto ensure only the right fields (likeemailandname) are saved to your database. - Resource Protection: Coral automatically caps
?limit=to prevent your server from being overwhelmed. For heavy traffic, also try express-rate-limit.
// Example: Using express-validator to sanitize inputs
const validateUser = [
body('email').isEmail(),
body('name').notEmpty(),
(req, res, next) => {
req.body = matchedData(req); // Only keep validated fields!
next();
}
];
Coral({ path: '/users', model: User, middlewares: [validateUser] });To contribute or run tests locally:
- Clone the repo:
git clone https://github.com/prathamesh7pute/coral.git - Install deps:
npm install - Build:
npm run build - Check:
npm run check(Lint & format) - Test:
npm test
Please see CONTRIBUTING.md for details on how to contribute and the process for submitting pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.