Best way to define custom functions in loopback api - node.js

What is the best way to define custom functions in loopback api that can be used in models defined ?
For example a basic express application can have functions in helper folder on root directory, but doing same in loopback is not recommended and does not maintain loopback way.
Any help would be highly appreciated.

This is very well documented.
Custom logic can be placed in
boot scripts
middlewares
models:
remote methods
remote hooks
operation hooks
application-decoupled logic can very well be put in helper folders, separate folders at root level, etc. There is nothing wrong with modularizing your program this way, it is actually a good thing.

As mentioned by others, the Loopback documentation answers your question like this:
Adding logic to models - adding remote methods, remote hooks and operation hooks.
Defining boot scripts - writing scripts (in the /server/boot directory) that run when the application starts.
Defining middleware - adding custom middleware to the application .
That's a great answer if you have custom functions for a particular model, boot script, or middleware. And as Dharmendra Yadav said, mixins can be another option:
You can use mixins to perform different common actions on models such as observing changes using operation hooks and adding model attributes.
But what about code that simply doesn't fit into any of those categories?
I don't have experience with a lot of web frameworks, but one framework I have used is Grails, which is very opinionated and gives you a place for just about everything. And if your code doesn't fit into any of those categories, they give you a place for that too:
src/main/groovy - Supporting sources
So when I ran into this same problem in Loopback, I just created a src directory under server and that's where I put some helper classes that don't seem to fit anywhere else. And I include them as needed:
const HelperClass = require('../src/HelperClass');
HelperClass.helperFunction()...
Of course you can name the folder however you'd like: src, helpers, support, whatever. And then put it under common or server as appropriate.

The best way to define functions in loopback i found is to use mixins. Here is the sample way of doing so..
https://loopback.io/doc/en/lb3/Defining-mixins.html
You can inherit these defined mixins into your models through .json of your model with {mixins:yourmixin.js}, nice and easy.

Here's some sample code to get you headed in the right direction.
mynewmodel.js
http://domain/api/mynewmodel/myfunc.js
function myfunc(data, callback) {
// ** Put your code here **
console.log('myfunc');
}
function remoteMethod(model) {
model.remoteMethod(
'myfunc',
{
http: { verb: 'post' },
accepts: { arg: 'data', type: 'data' },
returns: [
{ arg: 'returndata', type: 'data' }
]
}
)
}
UPDATE
Generally your js files go in common/models

Related

What is the best way to organize the code of a nodejs-express project, using TypeScript?

While trying to organize the code of my first NodeJS-express project, I ran into some doubts about the use of namespaces, modules and classes. When to choose one? When another?
For example, my project is structured (simplifying) in.
routers -> controllers -> services -> repositories.
The possibilities I thought of to manage these "entities" are the following:
Classes
Classes with static methods
Singletons
Simple module export
Namespaces
Classes
I thought of avoiding them right away, since the above-mentioned entities do not need to memorize any state. Furthermore, they would complicate the code due to the need to be instantiated.
Classes with static methods
They are correct? Or rather a simple namespace or simple export of the modules?
Class + Singletons
A way of organizing the code in a "nicer" way than the simple class, but which does not convince me, since reading on the net that the singleton in TypeScript is replaceable with the namespace.
Simple module export
The way I thought to implement immediately, for example in this way (file user.repository.ts):
const add = async (user: User): Promise<void> => {
if(await canBeAdded(user)) {
//save user;
} else {
// throw error
}
}
export const UserRepository = {
add
}
It's corrects? Or am I not properly using what TypeScript offers? Being the first time I use this language, I would like to be sure I chose the right path.
Namespaces
Are they a better choice to develop the code published above? Are you advised against?
Thank you in advance for the answers! Any advice is welcome!
P.S. I know that, once the TypeScript is compiled, in Javascript the classes are practically syntactic sugar. What I'm interested in knowing are the best practices for writing good code in TypeScript.

Writing ENV variables to configure an npm module

I currently have a project in a loose ES6 module format and my database connection is hard coded. I am wanting to turn this into an npm module and am now facing the issue of how to best allow the end user to configure the code. My first attempt was to rewrite it as classes to be instantiated but it is making the use of the code more convoluted than before so am looking at alternatives. I am exploring my configuration options. It looks like writing to the process env would be the way but I am pondering potential issues, no-nos and other options I have not considered.
Is having the user write config to process env an acceptable method of configuring an npm module? It's a bit like a global write so am dealing with namespace considerations for one. I have also considered using package.json but that's not going to work for things like credentials. Likewise using an rc file is cumbersome. I have not found any docs on the proper methodology if any.
process.env['MY_COOL_MODULE_DB'] = ...
There are basically 5ish options as I see it:
hardcode - not an option
create a configured scope such as classes - what I have now and bleh
use a config such as node-config - not really a user friendly option for npm
store as globals/env. As suggested in comment I can wrap that process in an exported function and thereby ensure that I have a complex non collisive namespace while abstracting that from end user
Ask user to create some .rc file - I would if I was big time like AWS but not in this case.
I mention this npm use case but this really applies to the general challenge of configuring code that is exported as functions. I have use cases for classes but when the only need is creating a configured scope at the expense (in my case) of more complex code I am not sure its worth it.
Update I realize this is a bit of a discussion question but it's helped me wrap my brain around options. I think something like this:
// options.js
let options = {}
export function setOptions(o) { options = o }
export function getOptions(o) { return options }
Then have the user call setOptions() and call this getOptions internally. I realize that since Node requires the module just once that my options object will be kept configured as I pass it around.
NPM modules should IMO be agnostic as to where configuration is stored. That should be left up to the developer, and they may pick their favorite method (env vars, rc files, JSON files, whatever).
The configuration can be passed to your module in various ways. A common way is to export a function that takes an options object:
export default options => {
let db = database.connect(options.database);
...
}
From there, it really depends on what exactly your module provides. If it's just a bunch of loosely coupled functions, you can just return an object:
export default options => {
let db = database.connect(options.database);
return {
getUsers() { return db.getUsers() }
}
}
If you want to allow multiple versions of that object to exist simultaneously, you can use classes:
class MyClass {
constructor(options) {
...
}
...
}
export default options => {
return new MyClass(options)
}
Or export the entire class itself.
If the number of configuration options is limited (say 3 or less), you can also allow them to be passed as separate arguments, instead of passing an object.

How to structure meteor app for testing

I'm reading through the online book Meteor Testing and am a bit concerned about how it says you should structure your app. It says to create an object in the global namespace called "App" and append submodules as needed, like this:
App = {
Services: {
func1: [some function]
func2: [some function]
...
},
Collections: {
func1: [some function]
func2: [some function]
...
}
...
}
My concerns are:
Will this negatively impact the security of my application?
Where and when should I defined functions within the app namespace? Adding all of them in one place would quickly get overwhelming.
Should I do this for all of the functions I want to unit test? If not, how do I access functions that I have defined within the scope of a template's javascript file?
If any of you could point me to additional resources on testing in meteor, I'd love to take a look at what other people suggest. Thanks.
You could sprinkle the definitions of all your functions among different files, but obviously load order would be important. I'd recommend creating a Meteor package for your project that would define all these functions and other globals needed, and then api.export('App') or api.export('App', 'client') (depending on your needs).

sails generate <something>: where are the docs on 'generate'?

sails generate controller <name> and model and api and others.
What are the others? What are the options? What are the commandline options?
Insert here the obligatory "I've websearched high and low" but the only thing I can come up with is github entries for individual generators in various states of ignorement.
So, abstractly, where's the documentation on the generate command?
The default generators shipped with Sails are documented here, in the command line interface section of the reference section of the Sails documentation. Where options are accepted I believe this section of the documentation references them, with sails new having the most option usage options.
At the time of writing they include new, api, model, controller, adapter, and generator.
More community created generators can be added, generally by modifying the .sailsrc file to include npm package. Here's an example from the sails-auth docs.
{
"generators": {
"modules": {
"auth-api": "sails-auth"
}
}
}
If you want to know more about making your own generators and what goes into that you'd probably want to check out the sails-generate-generator repo and docs.

Is it possible to group controllers in sails using subfolders?

I'm planning to organize my controllers in sails using subfolder but I'm not sure how to do it. When I tried using like admin/PageController.js and connect it with the route I keep getting a 404 error.
You can definitely do this. The trick is, the controller identity is its path, in your case admin/PageController. So a custom route in config/routes.js would be something like:
'GET /admin/page/foo': 'admin/PageController.foo'
The great thing is, automatic actions still work, so if you have an index action in the controller then browsing to /admin/page will automatically run it.
You can also create controllers like this with sails generate controller admin/page.
Edit
Since commit 8e57d61 you can do this to get blueprint routes and functionality on nested controllers, assuming there is an AdminPage model in your project:
// api/controllers/admin/PageController.js
module.exports = {
_config: {
model: 'adminpage'
}
}
or this:
// config/routes.js
module.exports.routes = {
'admin/page': {
model: 'adminpage'
}
}
Old Answer
Your options
Defining explicit routes to your grouped controllers in config/routes.js.
Look at Scott Gress' answer for more details.
(If you are a bit adventurous) As i had the exact same requirement for a project of mine I created a Pull Request on Sails that allows you to override the model - controller association. You could install it via
npm install -g git://github.com/marionebl/sails.git#override-controller-model
Assuming it is the api/models/Page.js model you want the blueprint methods for on api/controllers/admin/PageController.js you then could do:
// api/controllers/admin/PageController.js
...
module.exports = {
_config: {
model: 'page'
}
}
Explanation
While generating/creating grouped controllers like this is perfectly valid an possible, you will not get the default blueprint routes you'd expect for controllers accompanied by models with the same identity.
E.g. api/controllers/UserController.js and api/models/User.js share the same identity user, thus the blueprint routes are mounted if they are enabled in config/blueprints.js.
In fact at the moment it is not possible to group models into subfolders in a valid way. This means you won't be able to create a model that matches the identity admin/page of your controller api/controllers/admin/PageController.js - the blueprint routes are not mounted for PageController.
The source responsible for this behavior can be inspected on Github.
I made a diagram that shows how implicit routes, explicit policies, nested controllers, singular models and nested views are related. It does not show an overridden model-controller association as described by #marionebl.
It was mostly an exercise for me to understand this topic better, but I hope it helps somebody else too. Please let me know if I made any mistakes:
Thanks merionebl, its work fine for me and I want to share with all guys my answer derived from merionebl answer.
/config/routes.js
'get /admin/user' : {
controller: "Admin/UserController", action: "find",
model : 'user',
},
My aim is not repeat answer just have upgrade and clear example.
Thanks

Resources