loopbackio / loopback-next

LoopBack makes it easy to build modern API applications that require complex integrations.
https://loopback.io
Other
4.95k stars 1.07k forks source link

Unable to access request context within repository #2360

Closed mrvdot closed 5 years ago

mrvdot commented 5 years ago

Within a repository, I need to be able to access the current user for a request to check their permissions, however anytime I try (including just requesting RestBindings.Http.CONTEXT), I get a "key X was not bound to any value" error. Is there a way to do this, or do I need to pass it in from the controller for every method? I was previously using dependency injection, but that appears to not work anymore.

If you cannot access the RequestContext, how much of a risk is it to attach the user (and their session) to the app context? Is that likely to cause errors with multiple users making requests at the same time, or is the app context scoped securely?

I can provide the actual code if needed, but mostly I'm just looking for the best practice/architecture for accomplishing this.

Thanks

jannyHou commented 5 years ago

Hi @mrvdot I think it is the ~controller~action's responsibility to process the request context, invoke the controller method with needed information, instead of repository.

mrvdot commented 5 years ago

@jannyHou That does appear to be the requirement, it just seems strange. The whole point of IoC is to put the impetus for retrieving dependencies on the components that actually depend on them. For example, if I want to attach a default UserId to entities saved based on the current user, logically that should be in the repository as part of the create method. But it appears that because the repository has no awareness of the current request, I instead need to pass that user in from the controller for every method that the repository utilizes, for every single type of entity.

raymondfeng commented 5 years ago

By default, repositories are now TRANSIENT binding scope. If it's injected into a controller, which is in turn instantiated by a REST API call, the RequestContext should be available for your repository. Please re-open the issue if you see otherwise.

mrvdot commented 5 years ago

Thanks @raymondfeng , I'll test that out

cosad3s commented 3 years ago

Any update ? I am not able to access the request context within the repository. I tried the implementations withing this issue : https://github.com/strongloop/loopback-next/issues/1919, without success ... The HTTP context keeps to be "null".

raymondfeng commented 3 years ago

@cactuschibre How does your repository class look like?

cosad3s commented 3 years ago

@raymondfeng it is very simple, for example:

export class ClientRepository extends DefaultCrudRepository<
  Client,
  typeof Client.prototype.id
> {

  public readonly projects: HasManyRepositoryFactory<Project, typeof Client.prototype.id>;

  constructor(
    @inject('datasources.postgres') dataSource: PostgresDataSource, 
    @repository.getter('ProjectRepository') protected projectRepositoryGetter: Getter<ProjectRepository>,
  ) {
    super(Client, dataSource);
    this.projects = this.createHasManyRepositoryFactoryFor('projects', projectRepositoryGetter);
  }
}

And for the datasource :

@lifeCycleObserver('datasource')
export class PostgresDataSource extends juggler.DataSource
  implements LifeCycleObserver {
  static dataSourceName = 'postgres';
  static readonly defaultConfig = config;

  constructor(
    @inject('datasources.config.postgres', {optional: true})
    dsConfig: object = config,
  ) {
    super(dsConfig);
  }
}

And, like in the previous quoted issue, I tried to inject:

Then add:

  definePersistedModel(
    entityClass: typeof Product,
  ): typeof juggler.PersistedModel {
    const modelClass = super.definePersistedModel(entityClass);
    modelClass.observe('access', async ctx => {
      const httpCtx = await this.getHttpContext();
      console.log(httpCtx);
    });
    return modelClass;
  }

Or (in the constructor):

    (this.modelClass as any).observe('persist', async (ctx: any) => {
// Do something with the context on the 'persist' operation
    });

... Without effect. The HTTP context keeps to be null. The only context I get is the "data" transiting to the repository (Objet with data, hookState, options attributes).

I am using loopback/core 2.14.0.