-
Notifications
You must be signed in to change notification settings - Fork 131
Discussion: Autogenerating hooks #9
Comments
There are two other options... Idea 3: Flat but logically named
Idea 4: Flat and just the hook name
|
While #1 is a bit more verbose re: all folder I think it's more clear then just being in the root folder. I like the way it's all separated out. Easier to see what's going on vs just the flat structure |
👍 |
Ideally, we want a solution that
Since hooks can be highly reusable, we definitely need a general hooks library, but we also need a place to store hooks that are service specific. The only separation of hooks that makes sense to me is /before and /after, because hooks can be useful across multiple methods. So, to me, it doesn't make sense to use folders for the methods like /get and /patch unless we are going to number the files inside and have that be the hook execution order (which would result in a lot of copies of the same hooks, so it doesn't account for highly-reusable hooks). I think it makes sense to put each service in its own folder and include anything specific to the service in that folder, including the ORM model. More like this layout: I can see it being a fairly common scenario of starting out an app with multiple services in one server , then wanting to roll off a high-traffic service to its own machine/server. I think that this layout would facilitate that a little bit. Here's an example service's index.js: // index.js
import mongoose from 'mongoose';
import service from 'feathers-mongoose';
import User from './model';
import before from './before';
import after from './after';
mongoose.Promise = global.Promise;
export default function(){
const app = this;
mongoose.connect(app.get('mongodb'));
let options = {
Model: User,
paginate: {
default: 5,
max: 25
}
};
app.use('/v1/users', service(options));
// const service = this.service('v1/users');
/* * * Before hooks * * */
service.before(before);
/* * * After hooks * * */
service.after(after);
/* * * Set up event filters * * */
service.created = service.updated = service.patched = service.removed = events.requireAuthForPrivate;
} Each service could have a before.js and after.js with the hook configuration object in it. Having it by itself would keep it simple for a developer, but also make it easy to use with a GUI builder tool. Each service would also have its own // Bring in the global (highly-reusable) hooks.
import hooks from '../../hooks';
// Bring in hooks from the auth plugin.
import {hooks as authHooks} from 'feathers-authentication';
// Bring in service-specific hooks
import userHooks from './hooks';
export default before = {
all: [],
find: [],
get: [
authHooks.setUserID(),
userHooks.doSomething()
],
update: [],
patch: [],
delete: [
hooks.preventUserFromDeletingSelf()
]
}; In this scenario, I would like to see the |
Some notes from me:
|
I actually thought that same thing while I was writing the above. I'm not sure the separation is necessary. I've not encountered a case where I needed one of my after-hooks as a before- or vice versa. I tend to put the I'm still trying to figure out a nice way to show the hooks interface in the GUI. It would be nice for the user to be able to browse the installed hooks, as well as other community-shared hooks. We would need some sort of tagging system, or self-documenting system similar to what node machines does, in order for the library of hooks to be really accessible. That way we can add tags for |
There are basically four places that I can think of where we'll be defining hooks.
We are probably going to create a |
I'm picturing // jshint unused:false
import {hooks as auth} from 'feathers-authentication';
import {hooks as common} from 'feathers-commons';
let hooks = {
auth,
common
};
export default hooks; And maybe we could do the file system convention here as well. (where Then we would remove the line that says |
I'm not sure how to dynamically import modules in es6, since import statements have to be on the top level. Here's a quick module to handle importing the directory. // Read all hooks from the file system and arrange them into a single object.
import fs from 'fs';
let serviceHooks = {};
fs.readdir(__dirname, (err, files) => {
files.forEach(fileName => {
if (fileName.indexOf('.js') >= 0 && fileName !== 'index.js') {
fileName = fileName.replace('.js', '');
let camelCased = fileName.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
let module = require('./' + fileName);
module = module.default ? module.default : module;
serviceHooks[camelCased] = module;
}
});
});
export default serviceHooks; It supports either a default export or multiple keyed exports, but not both. |
Honestly, I'd rather have it imported explicitly. My experience was that those magical folder importing index files are always prone to errors (e.g. you can have really weird errors if you happen to put a file in that exports a function but not like we expect). I have a template to write the imports into the file I'll just have to finish that up this weekend. |
That works.
This is where an official hook spec would come in handy. We define the expectations. |
Yes but I mean e.g. someone accidentally (or purposely) puts a non-hook into the folder that happens to return a function. Also other questions like how do we handled nested folders etc.? |
Hah! from the code you can see that I was not even thinking about folders. |
Based on what we've talked about here, I'm closing this PR: https://github.com/feathersjs/generator-feathers/pull/15/files |
Ya @daffl and I discussed this same thing of automagically importing hooks last week. I should have included you in that discussion @marshallswain. We should be more cognoscente of putting all that stuff in either public domain or the core group in slack. I'll wrap the generator changes we have been talking about today and then I'm going to be working on the chat example/documenting it. |
If you are working on the generator, don't forget about #14 it has some code for adding the imports to the index file but it doesn't work yet. Still good to merge though I'd think. |
Yup sweet! Merging right meow. 😽 |
Soliciting some feedback for where hooks should go. Currently the way I'm generating them:
If you have a method that applies to all hooks for a service this would be fine. Here are some of my ideas.
Idea 1 (current implementation): deeply nested with an "all" group
Idea 2: deeply nested, hooks that apply to all are just top level
How option 1 would look in code
Advantage
It makes it very easy to track down where the hooks are. When building apps with lots of hooks it can be hard to keep track of them without an organized folder structure, especially if hooks in different services have the same name.
I think we want to encourage and make it as easy as possible to create a bunch of small hooks that do one thing well and chain them, rather than a few larger hooks that do a bunch of things.
Disadvantage
More boilerplate and scaffolding this out programatically from the generator is pretty complex.
The folder structure is easy, it's the
import
ing of the hook, the generating of theindex.js
file if it doesn't exist, and adding the path of a new hook to an existingindex.js
file that is complex and could be error prone.The text was updated successfully, but these errors were encountered: