Closed mrvdot closed 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.
@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.
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.
Thanks @raymondfeng , I'll test that out
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".
@cactuschibre How does your repository class look like?
@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:
@inject.getter(RestBindings.Http.CONTEXT) protected getHttpContext: Getter<Context>
@inject.getter(MiddlewareBindings.CONTEXT) protected getHttpContext: Getter<Context>
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.
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