Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Observe after access #441

Closed
cajoy opened this issue Feb 10, 2015 · 19 comments
Closed

Observe after access #441

cajoy opened this issue Feb 10, 2015 · 19 comments
Labels

Comments

@cajoy
Copy link

cajoy commented Feb 10, 2015

Add a new hook called loaded. It should be triggered whenever model data from the database is returned back to the caller (i.e. find but also create or prototype.updateAttributes) and the context should provide only ctx.instance, no ctx.data. For "batch" load like find, the hook should be fired multiple times, once for each model instance loaded.


The original issue description

I see there is couple of observers such as "access", "create" and etc.

What I need is "after find".

The reason is: I need to encrypt/decrypt data in database.

So basically before save I can encrypt data with the key.
But I can't decrypt data after find.

I've tried with getter/setter but it doesn't work.

@clark0x
Copy link
Contributor

clark0x commented Feb 12, 2015

the getter should work. Have you defined the encrypt property in model's json file?

@cajoy
Copy link
Author

cajoy commented Feb 12, 2015

I can't find any configuration for encrypt property in models json file.

So one of solutions is to use "before save" to encrypt and "getter" to decrypt... What may work. But

When I post the form, data comes as plain text decrypted. And for example I call validation on this property before saving it will try to decrypt property what is not encrypted what will cause an issue.

Example: Post form to save data

POST secureField - not encrypted
Model validation
"getter" secureField will try to decrypt (what will cause an issue)

Example: Get/Update from database

Model query
secureField is encrypted
"getter" secureField will decrypt the field
save model
observer "before save" will encrypt field
success

@ghost
Copy link

ghost commented Feb 19, 2015

This still seems like something that makes sense to have...and not just because every other operation hook has a before/after.

For example, if you merge one instance of a model into the other, then having an 'after access' hook would allow you to put a "redirectId" object in the old instance so that outdated references to the old model can be forwarded to the new model.

Right now this can be worked around in remote hooks by creating a wrapper module for the model, but is a problem when you start dealing with model relations and other things more tightly integrated into Loopback itself.

@bajtos bajtos self-assigned this Mar 6, 2015
@bajtos
Copy link
Member

bajtos commented Mar 6, 2015

The reason is: I need to encrypt/decrypt data in database.
So basically before save I can encrypt data with the key. But I can't decrypt data after find.

IMO, the hooks are not the right tool for transparent encryption of model properties (data), because the instance passed to "before save" hooks is then returned in the server response. The HTTP client will thus receive encrypted data, unless you implement also an "after save" hook that would decrypt them.

Could you please open a new issue in loopback requesting the feature for an easy way how to specify a different database representation of the model data?

For example, if you merge one instance of a model into the other, then having an 'after access' hook would allow you to put a "redirectId" object in the old instance so that outdated references to the old model can be forwarded to the new model.

This looks like reasonable usage of the new hook to me. Perhaps we can call the new hook "loaded"?

Just note that making database requests from such hook will incur performance overhead.

Ideally, LoopBack should provide a way how to fetch all related data (like your "redirectId") in a single request, either via SQL JOIN or using an appropriate NoSQL alternative. Since we don't support that yet, adding "loaded"/"after access" hook is a reasonable workaround.

@raymondfeng
Copy link
Contributor

+1 to add after access hook. That could be used by ACLs or custom logic to further transform the responses from a DB query.

@jmls
Copy link

jmls commented Mar 16, 2015

bugger. I need this functionality. gutted it's not in already.

@fabien
Copy link
Contributor

fabien commented Mar 16, 2015

+1 to after access as well

@raymondfeng
Copy link
Contributor

+1 to have after access.

@fabien
Copy link
Contributor

fabien commented Mar 16, 2015

Do we want to supply ctx.instance (obj?) and cx.data (array?) for this hook?

@drish
Copy link

drish commented Mar 17, 2015

+1 to after access

@bajtos
Copy link
Member

bajtos commented Mar 18, 2015

IMO, the hook should be called loaded, it should be triggered whenever model data from the database is returned back to the caller (i.e. find but also create or prototype.updateAttributes) and the context should provide only ctx.instance, no ctx.data. For "batch" load like find, the hook should be fired multiple times, once for each model instance loaded.

@fabien
Copy link
Contributor

fabien commented Mar 18, 2015

@bajtos fully agreed 👍

@drish
Copy link

drish commented Mar 18, 2015

loaded sounds good too, this functionality would be very useful.

@bajtos
Copy link
Member

bajtos commented Mar 31, 2015

IMO, the hooks are not the right tool for transparent encryption of model properties (data), because the instance passed to "before save" hooks is then returned in the server response. The HTTP client will thus receive encrypted data, unless you implement also an "after save" hook that would decrypt them.

Could you please open a new issue in loopback requesting the feature for an easy way how to specify a different database representation of the model data?

See strongloop/loopback#1260

@bajtos
Copy link
Member

bajtos commented Jun 26, 2015

Implemented by #599

@bajtos bajtos closed this as completed Jun 26, 2015
@bajtos bajtos removed the #wip label Jun 26, 2015
@akki-ng
Copy link

akki-ng commented Oct 13, 2017

@bajtos @raymondfeng has after access hook been implemented yet? I'm planning to do something similar to cursor pagination across system

loaded hook is being triggered for each row returned by the find

var p = app.registry.getModel("PersistedModel");
  p.observe("access", function logQuery(ctx, next) {
    console.log("Accessing %s matching %j", ctx.Model.modelName, ctx.query);

    next();
  });

  p.observe("loaded", function logQuery(ctx, next) {
    console.log(ctx.data);
    console.log("loaded %s matching %j", ctx.Model.modelName, ctx.query);

    next();
  });

  p.observe("after access", function logQuery(ctx, next) {
    console.log(ctx.data);
    console.log("after access %s matching %j", ctx.Model.modelName, ctx.query);

    next();
  });

@bajtos
Copy link
Member

bajtos commented Oct 16, 2017

@akki-ng

has after access hook been implemented yet?

Nope, we implemented "loaded" hook instead.

I can imagine how "after access" hook could be useful. Before it can be implemented, we need to carefully asses what would be the intended behavior for all our data-access methods.

If you would like to help with this feature, then please open a new GitHub issue and propose how would "after access" work for each methods listed in https://loopback.io/doc/en/lb3/Operation-hooks.html#overview. Will the hook be triggered or not? What will be the "context" properties for each operation?

@sidewaiise
Copy link

@bajtos I'm having issues with the 'loaded' implementation. If I create a new property on the ctx.data object within this hook, when next() is called, the new property does not return back to the user... is this a loopback-datasource-juggler versioning issue, or am I doing something wrong?

Here's a sample code snippet:

    Model.observe('loaded', function(ctx, next) {
        if(ctx.data) {
            ctx.data.newValue = [{title: 'one'}, { title: 'two' }, ...]
        }
        next()
    })

@bajtos
Copy link
Member

bajtos commented Dec 8, 2017

@sidewaiise I am not sure to be honest. Could you please open a new issue and provide us a sample app reproducing the problem per our instructions? This may be a problem of a specific data-access method not honoring the updated ctx.data values.

@loopbackio loopbackio locked and limited conversation to collaborators Dec 8, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

10 participants