MinAPI Models Reference
The models system in MinAPI is a powerful abstraction over MongoDB collections that provides schema validation, CRUD operations, and data transformations.
Model Definition
Models are defined in the models section of your minapi.config.js file:
models: {
Users: {
collection: 'user',
labels: ['User', 'Users'],
values: {
_id: ['ObjectId', 'rd'],
email: ['String', 'cru'],
password_hash: ['String', 'c'],
created_at: ['Date', 'r'],
updated_at: ['Date', 'r']
},
filters: {
// Filter functions
}
}
}
Model Properties
collection
The name of the MongoDB collection this model represents:
collection: 'user'
labels
Human-readable labels for the model (singular and plural):
labels: ['User', 'Users']
values
The schema definition for the model, which defines fields, their types, and CRUD permissions:
values: {
field_name: ['DataType', 'crudOperations', defaultValue]
}
Each field definition consists of:
DataType: The type of the field (String,Number,Date,Boolean,ObjectId,Array)crudOperations: A string containing which operations are allowed:c: Create - Field can be set when creating a recordr: Read - Field can be readu: Update - Field can be updatedd: Delete - Field can be used in delete conditions
defaultValue(optional): Default value if none is provided
filters
Functions that process data during CRUD operations:
filters: {
// Global filters
where: (whereObject) => { /* modify and return whereObject */ },
values: (valuesObject) => { /* modify and return valuesObject */ },
output: (outputData) => { /* modify and return outputData */ },
// Operation-specific filters
create: {
where: (whereObject) => { /* modify and return whereObject */ },
values: (valuesObject) => { /* modify and return valuesObject */ }
},
// Additional operation filters...
}
Database Operations
Once you have defined a model, MinAPI provides a set of database operations through the API.DB object:
Create
// Create a single document
const user = await API.DB.Users.create({
email: 'user@example.com',
password_hash: await API.Auth.hash('password123')
});
// Create multiple documents
const users = await API.DB.Users.createMany([
{ email: 'user1@example.com', password_hash: await API.Auth.hash('password123') },
{ email: 'user2@example.com', password_hash: await API.Auth.hash('password456') }
]);
Read
// Read a single document by ID
const user = await API.DB.Users.read({ _id: '60d21b4667d0d8992e610c85' });
// Read with custom query
const user = await API.DB.Users.read({ email: 'user@example.com' });
// Read all documents matching criteria
const adminUsers = await API.DB.Users.readAll({ role: 'admin' });
// Read or create (returns existing document or creates new one)
const user = await API.DB.Users.readOrCreate(
{ email: 'user@example.com' }, // Where condition
{ email: 'user@example.com', password_hash: await API.Auth.hash('password123') } // Values to create if not found
);
Update
// Update a single document
const updatedUser = await API.DB.Users.update(
{ _id: '60d21b4667d0d8992e610c85' }, // Where condition
{ email: 'newemail@example.com' } // New values
);
// Update multiple documents
const result = await API.DB.Users.updateAll(
{ role: 'user' }, // Where condition
{ verified: true } // New values
);
Delete
// Delete a single document
const result = await API.DB.Users.delete({ _id: '60d21b4667d0d8992e610c85' });
// Delete multiple documents
const result = await API.DB.Users.deleteAll({ role: 'guest' });
Filter System
Filters are powerful functions that can modify data during database operations.
Filter Types
- Global filters:
where: Modifies query conditions for all operationsvalues: Modifies data being saved to the databaseoutput: Modifies data being returned from the database
- Operation-specific filters:
create.where/create.values: For create operationscreateMany.where/createMany.values: For createMany operationsread.where: For read operationsreadAll.where: For readAll operationsupdate.where/update.values: For update operationsupdateAll.where/updateAll.values: For updateAll operationsdelete.where: For delete operationsdeleteAll.where: For deleteAll operations
Filter Execution Flow
When a database operation is performed, filters are applied in this order:
- Global filters (if defined)
- Operation-specific filters (if defined)
- Sanitization based on the model’s values definition
Example Use Cases
Data Encryption/Decryption
Users: {
// ... other model properties
filters: {
values: (values) => {
// Encrypt sensitive data before storing
if (values.access_token) {
values.access_token = API.Utils.tokenEncrypt(values.access_token);
}
return values;
},
output: (output) => {
// Decrypt sensitive data when reading
if (output && output.access_token) {
output.access_token = API.Utils.tokenDecrypt(output.access_token);
}
return output;
}
}
}
Adding Timestamps
Users: {
// ... other model properties
filters: {
create: {
values: (values) => {
values.created_at = new Date();
values.updated_at = new Date();
return values;
}
},
update: {
values: (values) => {
values.updated_at = new Date();
return values;
}
}
}
}
Access Control
Posts: {
// ... other model properties
filters: {
readAll: {
where: (where) => {
// Add tenant filtering for multi-tenant applications
if (global.currentUser && !global.currentUser.is_admin) {
where.organization_id = global.currentUser.organization_id;
}
return where;
}
}
}
}
Foreign Key Relationships
MinAPI uses a naming convention for foreign keys: use the collection name with _id suffix:
models: {
Users: {
collection: 'user',
// ...
},
Posts: {
collection: 'post',
values: {
// ...
user_id: ['ObjectId', 'cru'], // Reference to the user collection
}
}
}
Best Practices
- Consistent Collection Naming: Use singular form for collection names
- Field Naming Conventions: Use snake_case for field names
- Foreign Keys: Always use
collection_name_idformat - Default Values: Provide sensible defaults for required fields
- CRUD Permissions: Be restrictive with permissions, especially for sensitive fields
- Keep Filters Pure: Filters should not have side effects and should always return a value