Angular 5 HTTP Interceptor not setting withCredentials - angular5

I need to intercept all of my http calls and set {withCredentials : true }.
So I built the following interceptor.
#Injectable()
export class HttpsRequestInterceptor implements HttpInterceptor {
constructor(private router: Router) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const changedReq = req.clone({withCredentials:true});
return next.handle(changedReq);
}
}
I placed a debugger to make sure it is running. and it runs fine in all requests.
The problem that the {withCredentials:true} is being ignored, unless I put it within every post and post. (which is why I have created this).
What am I doing wrong?
Thanks

Related

Nestjs early return in interceptor sends [ERR_HTTP_HEADERS_SENT]

I am using interceptor on a controller to feed mock data if user is tagged as a demo user in the jwt
It works fine, mock data are fed to client and request doesn't reach my controller, but I still get following error in console :
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
This is my interceptor :
#Injectable()
export class UserPageStatsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// Let controller handle request
if (!isDemo(context)) {
return next.handle();
}
// Feed mock datas
const res = context.switchToHttp().getResponse();
res.status(200).send('Demo data');
}
}
And here is my controller :
#Get('statistics')
#UseInterceptors(UserPageStatsInterceptor)
getUsersGlobalStatistics(
#Headers() headers: CustomHeaders,
#Query() filters: BasicFiltersDTO,
#Req() req,
): Promise<UserStatisticsDTO> {
return 'Real data';
}
I suspect that after my UserPageStatsInterceptor the request continues somewhere in the internal of nestjs framework but I haven't been able to find out where.
I have tried adding a returnor res.end() at the end but it doesn't change anything.
Note that this only happens when making queries on my frontend client and doesn't happen in postman
Thank you in advance guys !!
Instead of calling res.send() inside of your interceptor, why not just return an observable that has the data you want to return?
#Injectable()
export class UserPageStatsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// Let controller handle request
if (!isDemo(context)) {
return next.handle();
}
return of('Demo data');
}
}
This will let Nest still handle the response, and not get in the way of actually running your service code.

Http post and get request in angular 6

In angular 5.2.x for http get and post I had this code:
post(url: string, model: any): Observable<boolean> {
return this.http.post(url, model)
.map(response => response)
.do(data => console.log(url + ': ' + JSON.stringify(data)))
.catch(err => this.handleError(err));
}
get(url: string): Observable<any> {
return this.http.get(url)
.map(response => response)
.do(data =>
console.log(url + ': ' + JSON.stringify(data))
)
.catch((error: any) => Observable.throw(this.handleError(error)));
}
In angular 6 it doesn't work.
How can we make an HTTP post or get request?
Update :
In angular 7, they are the same as 6
In angular 6
the complete answer found in live example
/** POST: add a new hero to the database */
addHero (hero: Hero): Observable<Hero> {
return this.http.post<Hero>(this.heroesUrl, hero, httpOptions)
.pipe(
catchError(this.handleError('addHero', hero))
);
}
/** GET heroes from the server */
getHeroes (): Observable<Hero[]> {
return this.http.get<Hero[]>(this.heroesUrl)
.pipe(
catchError(this.handleError('getHeroes', []))
);
}
it's because of pipeable/lettable operators which now angular is able to use tree-shakable and remove unused imports and optimize the app
some rxjs functions are changed
do -> tap
catch -> catchError
switch -> switchAll
finally -> finalize
more in MIGRATION
and Import paths
For JavaScript developers, the general rule is as follows:
rxjs: Creation methods, types, schedulers and utilities
import { Observable, Subject, asapScheduler, pipe, of, from, interval, merge, fromEvent } from 'rxjs';
rxjs/operators: All pipeable operators:
import { map, filter, scan } from 'rxjs/operators';
rxjs/webSocket: The web socket subject implementation
import { webSocket } from 'rxjs/webSocket';
rxjs/ajax: The Rx ajax implementation
import { ajax } from 'rxjs/ajax';
rxjs/testing: The testing utilities
import { TestScheduler } from 'rxjs/testing';
and for backward compatability you can use rxjs-compat
You can do a post/get using a library which allows you to use HttpClient with strongly-typed callbacks.
The data and the error are available directly via these callbacks.
The library is called angular-extended-http-client.
angular-extended-http-client library on GitHub
angular-extended-http-client library on NPM
Very easy to use.
Traditional approach
In the traditional approach you return Observable<HttpResponse<T>> from Service API. This is tied to HttpResponse.
With this approach you have to use .subscribe(x => ...) in the rest of your code.
This creates a tight coupling between the http layer and the rest of your code.
Strongly-typed callback approach
You only deal with your Models in these strongly-typed callbacks.
Hence, The rest of your code only knows about your Models.
Sample usage
The strongly-typed callbacks are
Success:
IObservable<T>
IObservableHttpResponse
IObservableHttpCustomResponse<T>
Failure:
IObservableError<TError>
IObservableHttpError
IObservableHttpCustomError<TError>
Add package to your project and in your app module
import { HttpClientExtModule } from 'angular-extended-http-client';
and in the #NgModule imports
imports: [
.
.
.
HttpClientExtModule
],
Your Models
export class SearchModel {
code: string;
}
//Normal response returned by the API.
export class RacingResponse {
result: RacingItem[];
}
//Custom exception thrown by the API.
export class APIException {
className: string;
}
Your Service
In your Service, you just create params with these callback types.
Then, pass them on to the HttpClientExt's get method.
import { Injectable, Inject } from '#angular/core'
import { SearchModel, RacingResponse, APIException } from '../models/models'
import { HttpClientExt, IObservable, IObservableError, ResponseType, ErrorType } from 'angular-extended-http-client';
.
.
#Injectable()
export class RacingService {
//Inject HttpClientExt component.
constructor(private client: HttpClientExt, #Inject(APP_CONFIG) private config: AppConfig) {
}
//Declare params of type IObservable<T> and IObservableError<TError>.
//These are the success and failure callbacks.
//The success callback will return the response objects returned by the underlying HttpClient call.
//The failure callback will return the error objects returned by the underlying HttpClient call.
searchRaceInfo(model: SearchModel, success: IObservable<RacingResponse>, failure?: IObservableError<APIException>) {
let url = this.config.apiEndpoint;
this.client.post<SearchModel, RacingResponse>(url, model,
ResponseType.IObservable, success,
ErrorType.IObservableError, failure);
}
}
Your Component
In your Component, your Service is injected and the searchRaceInfo API called as shown below.
search() {
this.service.searchRaceInfo(this.searchModel, response => this.result = response.result,
error => this.errorMsg = error.className);
}
Both, response and error returned in the callbacks are strongly typed. Eg. response is type RacingResponse and error is APIException.
For reading full response in Angular you should add the observe option:
{ observe: 'response' }
return this.http.get(`${environment.serverUrl}/api/posts/${postId}/comments/?page=${page}&size=${size}`, { observe: 'response' });

How to Create Aurelia Services without Redundant Header Configuration?

I'm currently working on a project using Aurelia as the front-end framework, and I'm wondering if there's a more eloquent and less redundant way to set the request header in my API services. The following is an example.
In this Post service, I have created a configureHeaders method that I'm calling prior to every API call because, otherwise, I run into the case where the web token has changed but the request header isn't updated. While creating this configureHeaders method is a functional workaround, I have to do it for each of my services, and it's feeling very redundant.
Is there a way to configure the request header application-wide so that I don't have to create a configureHeaders method for each service and call it for each request?
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-http-client';
import environment from 'environment';
#inject(HttpClient)
export class Post {
constructor(http) {
this.http = http;
}
configureHeaders() {
this.token = window.localStorage.getItem('token') || null;
this.http = this.http
.configure(x => {
x.withBaseUrl(environment.serverBaseURL);
x.withHeader('Authorization', `Bearer ${this.token}`);
});
}
getPosts() {
this.configureHeaders();
return this.http.get('post')
.then(posts => {
return JSON.parse(posts.response);
});
}
}
As R.Richards commented, Aurelia's HttpClient Interceptor is what you're after.
Here's a class example - as opposed to object with anonymous functions
1.) Declare the interceptor
import {Interceptor, HttpResponseMessage, RequestMessage} from 'aurelia-http-client'
export class CustomInterceptor implements Interceptor {
request(request: RequestMessage): RequestMessage {
//Do request interceptor here
return request;
}
response(response: HttpResponseMessage): HttpResponseMessage{
//Do response interception here
return response;
}
}
2.) Register the interceptor as part of your default http client within your main.js
import {CustomInterceptor} from 'path/to/custom-interceptor'
...
...
http.configure(config => {
//config stuff here
).withInterceptor(new CustomInterceptor())
This should suit your eloquence!

How to pass values from one class's method to another class's method in Typescript?

I'm new to Object Oriented programming and am assuming this should be an easy concept for the seasoned OO programmers, but I'm certainly struggling with it.
In my Angular2 app I have a HttpService class as shown below:
http.service.ts
#Injectable()
export class HttpService {
constructor(private http: Http) { }
addLeaf(parentId, label, name){
var headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://localhost:8000/addleaf/',
{'parentId':parentId,'label':label, 'name':name},
{ headers: headers })
.map(res => res).subscribe();
}
I try to call this method from within another class as below:
leaf.ts
import { HttpService } from './http.service';
export class Leaf{
name: string;
...
http: Http; // very unsure about these two lines
private httpService: HttpService = new HttpService(this.http)
constructor(input){
this.name = input.name;
...
add(){
//what should go here?
this.httpservice.addLeaf(this.id, this.label, this.name);
//error -> cannot read property 'post' of undefined
}
Reading this, I tried creating an instance of the HttpService class but I get the error that the post function does not exist. Also no luck putting the httpService in the constructor.
I call the method in my html like this:
(click)="leaf.add()"
EDIT: following #peeskillet's answer I modified leaf.ts and added leaf.component.ts as shown:
leaf.ts
export class Leaf{
name: string;
...
constructor(input){
this.name = input.name;
...
add(){
//what should go here?
}
}
leaf.component.ts
#Component({
providers: [HttpService],
})
export class LeafComponent {
leaf: Leaf;
constructor(private httpService: HttpService) {
this.httpService.addLeaf(this.leaf.id, this.leaf.type, this.leaf.name)
}
}
service works fine if I write pre-defined strings in place of the params, but still not sure how I can pass the parameters of the clicked leaf to this.
With Angular, we use dependency injection and Inversion of Control. What this means is that we do not create the service ourselves, but let Angular create it. Then we just ask for the service, then Angular will resolve any dependencies that service has. Take for example
#Injectable()
class Service {
constructor(private http: Http) {}
}
Here, Service has a dependency in Http. Http is not something that we can just grab out of thin air. We can't just do
let service = new Service(new Http());
Http is also dependent on some other services. Here what its constructor looks like
class Http {
constructor(backend: ConnectionBackend, options: RequestOptions) {}
}
You might think that maybe you can just instantiate it with the ConnectionBackend and RequestOptions
new Http(new ConnectionBackend(), new RequestOptions())`
But you can't do this either, as ConnectionBackend also has required dependencies. It's for this reason that we use Inversion of Control. We just add the service to a container, and when ask for the service, Angular look look up service, as see that it requires, Http, and see that Http requires ConnectionBackend and RequestOptions, etc, and Angular will create all the items, looking in its registry for all those items and putting them all together like Voltron. Then it will give us the service, fully populated.
So add our service to the container, we first need to add the Injectable decorator on the service
#Injectable()
class Service {
constructor(private http: Http) {}
}
Then we need to add it to the #NgModule.providers
#NgModule({
imports: [ HttpModule ],
providers: [ Service ]
})
class AppModule {}
Now, whenever we ask for Service, it will be fully populated with the Http (which is in the HttpModule).
How we ask for the service is through the constructor of either another service or component (directive, pipe, etc)
#Component({
})
class MyComponent {
constructor(private service: Service) {}
}
By seeing the Service type as a constructor argument, Angular knows to look up the Service in its container, then pass it through to us. This is the basics of Dependency Injection and Inversion of Control.
In your case of Leaf. If is is meant to be a service, then you can do the same
#Injectable()
class Leaf {
constructor(private service: Service) {}
}
#NgModule({
imports: [ HttpModule ],
providers: [ Leaf, Service ]
})
class AppModule {}
If you don't want to add Leaf as a provider, you don't need to. Just do
#Component({})
class MyComponent {
leaf: Leaf;
constructor(private service: Service) {
this.leaf = new Leaf(service);
}
}

Setting Headers (token) of multiple objects once user is authenticated in Angular2

Hi I've created a generic service from which I can create objects with generic http requests.
The challenge I'm facing now is to pass to each created object a token into their headers if the user is authenticated (i will get a token as response, which is stored in the localStorage)
So basically I can create these custom http objects anywhere (component-wise by injection) on any level. All of them don't have the Authentication Header set yet. Once User is authenticated, all these object to have their Authentication Header set.
Here's the plunker
export class App {
myHttpObject1;
constructor(private myAuth:MyAuth, private myDatabase:MyDatabase) {
this.name = 'Angular2 (Release Candidate!)'
this.myHttpObject1 = this.myDatabase.httpSchema('users')
this.myHttpObject1.log()
// this.myHttpObject1.someOtherMethodes()...
}
login(){
this.myAuth.login()
}
showHeaders(){
this.myHttpObject1.log()
}
}
Below is the Service and one to mock a login.
#Injectable()
export class MyDatabase{
private base_url:string;
private headers :Headers;
constructor(){
this.base_url = 'https://jsonplaceholder.typicode.com/';
this.headers = new Headers();
this.headers.append('Content-Type', 'application/json');
this.headers.append('Authorization','');
}
public httpSchema(path:string){
return new MyHttpObject(path, this.headers || new Headers())
}
}
class MyHttpObject{
constructor(public url:string, public headers:Headers){
}
log(){
console.log(this.url)
console.log(this.headers)
}
post(){
console.log('here could be a http post')
}
}
#Injectable()
export class MyAuth{
login(){
setTimeout(()=>{
console.log('logged In');
localStorage.setItem('token':'mytoken');
},2000)
}
}
Look at the Http Injector, it intercepts the call and adds whatever you need to the http object.