Home | Documentation | Core | CLI | Install |
Home > Documentation > Dependency Manager > Dynamic Resources
- Config
- Controller
- Dependency Manager
- Dynamic Resources
- Properties
- Static Resources
- Model
- Service
- View
Dependency Manager
Dynamic Resources
Dynamic resources are loaded according to Co.Koa’s conventions. Controllers, Services, Views and Models must all be stored in their respective folders. Services and Controllers must be suffixed with Service
and Controller
respectively. For example:
./api/controllers/TestController.js
./api/services/TestService.js
while you may place unconventional js files in conventional locations, co-koa-core
will neither route nor expose anything it doesn’t recognise. Crucially, models are not suffixed with the word Model
(since they represent like-for-like the real-world data you want your application to store and consume). It is important, therefore, that only models are placed inside the ./api/models
folder!
Presently, Services, Models and Validators can be accessed dynamically via the Dependency Manager wherever it is exposed:
const sampleService = $('SampleService'); // load an instance of SampleService in ./api/services/SampleService.js
const Sample = $('Sample') // call a Mongoose model instance derived from the Sample schema in ./api/models/Sample.js
const SampleValidator = $('SampleValidator') // call a validator library for your mongoose instance from ./api/models/validators/SampleValidator.js
Caveats
Be careful to avoid accessing dependencies cyclically. An example would be allowing the the full function block of a model to load itself. Suppose we have Sample.js
as a model, and we call $('Sample')
at the top of the function:
module.exports = function Sample ($) {
const Sample = $('Sample'); // CRASH CRASH CRASH!
return {
...
}
}
The above will crash the server. as will calling the service below in the Sample Model:
// SampleService.js
module.exports = function SampleService ($) {
const Sample = $('Sample');
return {
...
}
}
// Sample.js (model)
module.exports = function Sample ($) {
const sampleService = $('SampleService'); // CRASH CRASH CRASH!
return {
...
}
}
However, there are legitimate instances where loading an ostensibly cyclical dependency will work just fine; provided that the cyclical reference is loaded within the scope of a callback.
For Example the co-koa-mongoose-plugin
that ships with Co.Koa can load in a model cyclically via a callback; this allows you to cross reference an existing document before/after a mongoose event is actioned.
Since Mongoose doesn’t ship with a traditional ‘Unique’ validator, this is a good tactic for validating unique fields in Mongoose before saving a document. See below:
module.exports = function Sample ($) {
return {
...
hooks: {
pre: {
async save (next) {
// check if a document has the same "name" as the new document the user is trying to create
if (this._doc.hasOwnProperty('name')) {
const Model = $('Sample');
const hasModel = await Model.findOne({ name: this._doc.name });
if (hasModel) throw new Error('The name field is not unique!');
}
next()
}
}
}
}
}