Reputation: 422
I've got a very practical usable question which probably has some fancy Angular Dependency Injection solution.
Basically:
I have Interceptor A to provide an Auth Header for communicating with Service A.
And I have Interceptor B to provide an Auth Header for communicating with Service B.
How do I get every instance of Service A to have the Interceptor chain with Interceptor A? And how do I guarantee the opposite for Service B?
Both Services are used globally throughout the app so I can't don't think I can define a new HTTP_INTERCEPTOR Injection token only in the modules where Service B / A is used.
Thank you!
Upvotes: 4
Views: 3731
Reputation: 422
Just in case anyone has this issue in the future, this is what I ended up doing.
I needed to add STATIC headers to an HttpRequest but this solution can be easily modified to allow more dynamic headers.
I made an Attribute Adding Interceptor with the following:
attribute.interceptor.ts
@Injectable()
export class AttributesInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const attributes = environment.attributes;
let attributeReq = req;
for (let i = 0; i !== attributes.length; i++) {
const attribute = attributes[i];
if (this.urlMatches(attribute.urls, req)) {
// The url matches so let's apply the attribute
attributeReq = attributeReq.clone({ headers: req.headers.set(attribute.header, attribute.value) });
}
}
return next.handle(attributeReq);
}
urlMatches(urls: string[], req: HttpRequest<any>): boolean {
for (let i = 0; i !== urls.length; i++) {
if (req.url.includes(urls[i])) {
return true;
}
}
return false;
}
}
And defined my static attributes in the environment file:
environment.local.ts
export const endpoints = {
midway: 'http://localhost:8080',
builds: 'http://localhost:7245'
};
export const environment = {
production: false,
logLevel: LogSeverity.INFO,
endpoints: endpoints,
attributes: <Attribute[]> [
{
header: 'X-COMPANY',
value: 'SECRET-TOKEN',
urls: [ endpoints.midway ]
}
]
};
Where an Attribute is defined as:
export class Attribute {
header: string;
value: string;
urls: string[];
}
So now I can add specific static headers to any service call and just append the this attribute array with the service base url and the header / value.
This solution can be extended to serve a lot more complicated use cases but this simple solutions does exactly what I need!
Upvotes: 0
Reputation: 222319
Considering that both services are registered on root injector, the only way to do that is to create a new module that is similar to HttpClientModule
but has new DI tokens - HttpClientB
instead of HttpClient
and HTTP_INTERCEPTORS_B
instead of HTTP_INTERCEPTORS
. This will requite to extract several internals from common/http/src
because they aren't exported, e.g. interceptingHandler
.
This way it's possible for service B to have its own injectors in HTTP_INTERCEPTORS
and inject HTTP client as HttpClientB
.
A simpler way is to have an interceptor that is able to switch between implementations depending on input. As shown here, the only ways to interact with interceptor during request is to pass data via request parameters or headers.
So service A can do requests like:
http.get(..., { headers: new HttpHeaders({ useAuth: 'A' }) });
And interceptor receives the header and makes a decision based on it:
intercept(req, next) {
if (req.headers.get('useAuth') === 'A') ...
else if (req.headers.get('useAuth') === 'B') ...
else ...
req.headers = req.headers.delete('useAuth'));
}
If interceptors A and B are specific only to services A and B but not to the rest of the application, interceptors shouldn't be used at all. Instead this should be done directly in services A and B.
Upvotes: 3