Intercept requests from dataManager

In angular we have twi interceptors to provide the full api base url and an JWT for authorization:

Interceptor for api base url:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  if (!req.url.startsWith("http://"&& !req.url.startsWith("https://")) {
    console.log("Intercepted call: " + req.url)
    this.apiUrl = this.appSettingsService.GetSettingByName("Configuration.ApiUrl").replace(/\/$/"");
 
    if (!this.apiUrl) {
      throw new Error("API URL is empty.");
    } else {
      const apiReq = req.clone({
        url: `${this.apiUrl}${req.url}`
      });
      return next.handle(apiReq);
    }
  } else {
    console.log("Un-intercepted call: " + req.url)
    return next.handle(req);
  }
}

Interceptor for web tokens:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // add authorization header with jwt token if available
    if (this.tokenService.tokenExists()) {
      let token = this.tokenService.getToken();
      request = request.clone({
        setHeaders: {
          //'Content-Type': 'application/json; charset=utf-8',        
          'Authorization'`Bearer ${token}`
        }
      });
    }
 
    return next.handle(request);
  }

As we saw, your calls from the Datamanager (UrlAdaptor) are not calls via HttpRequest, they are XMLHttp-Calls, so all of our interceptors are not working for your datamanager. Is there any possibility to get our interceptors working without declaring other interceptors for XMLHttp-Request?
We don't want to have so many interceptors and only those two.

We already tried to create a new adaptor and override the "onBefore" method to manually manupulate the url, but that didn't work. The url of the request is used, not the manupulated one:

class CustAdaptor extends UrlAdaptor {
  constructor(private baseurl: string) {
    super();
  }
  beforeSend(dm: DataManager, request: XMLHttpRequest) {
    
    let url = this.baseurl + dm.dataSource.url;
 
    dm.dataSource.url = url;
    //settings.setRequestHeader("Hallo", "lalalalla");
  }
}
If that works, that would be workaround until we can use httprequest interceptors.




9 Replies

PS Pavithra Subramaniyam Syncfusion Team May 22, 2018 01:25 PM UTC

Hi Marco, 

Thanks for contacting Syncfusion support. 

We have checked your query and before providing solution to your query could you please share the below details that will be helpful for us to provide a better solution as early as possible. 

  1. Do you want to set only header to the request?
  2. Do you need to send any additional parameter along with request?

Regards, 
Pavithra S. 



MF Marco Franke May 22, 2018 01:28 PM UTC

Hello!

  1. Do you want to set only header to the request?
    Yes, this header is provided on every request by our interceptor

  1. Do you need to send any additional parameter along with request?
    At the moment we only need to pass the header and provide the base url of the API in our interceptors.


PS Pavithra Subramaniyam Syncfusion Team May 24, 2018 03:27 AM UTC

Hi Marco, 

In Essential JavaScript 2 DataManager, all requests to the server will be sent as XmlHttpRequests by default. However if you want to change the URL, you can directly assign the customized one in the DataManager.Url property. You can also set the headers using the DataManager.headers property. Please refer to the below code example and sample link. 

[component.ts] 
@Component({ 
  selector: 'app-root', 
  template:` <ejs-grid [dataSource]='data'> 
                .   .   . 
                </ejs-grid>`, 

}) 
export class AppComponent implements OnInit { 
  .   .   . 
  @ViewChild('grid') 
  public grid: GridComponent; 

  ngOnInit(): void { 
   this.baseUrl = window.location.rel='nofollow' href; 

    this.pData = new DataManager({ 
      url: this.baseUrl + 'Home/UrlDataSource',   // customized URL 
      adaptor: new UrlAdaptor, 
      headers: [{ 'Authenticcation': 'bearer123' }]   //set the header 
    }); 
  } 



Regards, 
Pavithra S. 



MF Marco Franke May 24, 2018 08:29 AM UTC

Thank you for your reply.
Currently we are using this approach but we don't want to provide the base url in every component because we will have more than a few components.

Our goal is to keep the source code for request simple as possible for the developers. They don't have to care about the base url and the appropiate header, since we are going to handle this in seperate services.

The question is, can we use your Datamanager with HttpRequests, so that our interceptors will work?
Or do we have the chance to catch your XMLRequests within a new adaptor and provide the header and the base url in one central way?


PS Pavithra Subramaniyam Syncfusion Team May 25, 2018 12:10 PM UTC

Hi Marco, 

You can achieve your requirement by using beforeSend() method of CustomAdaptor  which is extended from the default UrlAdaptor. In that method you can change the url property of XmlHttpRequest by using open() method and set the header by using dataMaanger.headers property. We have prepared a simple sample based on your query. Please refer to the below code example and sample link. 

[adaptor.ts] 
export class CustomAdaptor extends UrlAdaptor { 
    beforeSend(dm: DataManager, request: XMLHttpRequest) { 
        request.open('POST', 'UrlDatasource');                                    // customizing the Url of lHttpRequest 
       request.setRequestHeader('Content-Type', 'application/json; charset=utf-8'); 
        dm.dataSource.headers = [{ 'Authorization': 'bearertoken' }];  // setting header 
    } 
} 

[component.ts] 
@Component({ 
    selector: 'fetchdata', 
    template: ' <ejs-grid #grid [dataSource]='pData' height='265px' [childGrid]='childGrid' [editSettings]='editSettings' [toolbar]='toolbar'> 
    <e-columns> 
   .  .  . 
    </e-columns> 
</ejs-grid>', 
    encapsulation: ViewEncapsulation.Emulated 
}) 
export class FetchDataComponent { 
 
    @ViewChild('grid') 
    public grid: GridComponent; 
 
    ngOnInit(): void { 
        this.pData = new DataManager({ 
            url: 'Home/EmployeeDatasource', 
            adaptor: new CustomAdaptor, 
        }); 
    .  .  . 
       }  
} 



Regards, 
Pavithra S. 



MF Marco Franke replied to Pavithra Subramaniyam May 25, 2018 01:35 PM UTC

Hi Marco, 

You can achieve your requirement by using beforeSend() method of CustomAdaptor  which is extended from the default UrlAdaptor. In that method you can change the url property of XmlHttpRequest by using open() method and set the header by using dataMaanger.headers property. We have prepared a simple sample based on your query. Please refer to the below code example and sample link. 

[adaptor.ts] 
export class CustomAdaptor extends UrlAdaptor { 
    beforeSend(dm: DataManager, request: XMLHttpRequest) { 
        request.open('POST', 'UrlDatasource');                                    // customizing the Url of lHttpRequest 
       request.setRequestHeader('Content-Type', 'application/json; charset=utf-8'); 
        dm.dataSource.headers = [{ 'Authorization': 'bearertoken' }];  // setting header 
    } 
} 

[component.ts] 
@Component({ 
    selector: 'fetchdata', 
    template: ' <ejs-grid #grid [dataSource]='pData' height='265px' [childGrid]='childGrid' [editSettings]='editSettings' [toolbar]='toolbar'> 
    <e-columns> 
   .  .  . 
    </e-columns> 
</ejs-grid>', 
    encapsulation: ViewEncapsulation.Emulated 
}) 
export class FetchDataComponent { 
 
    @ViewChild('grid') 
    public grid: GridComponent; 
 
    ngOnInit(): void { 
        this.pData = new DataManager({ 
            url: 'Home/EmployeeDatasource', 
            adaptor: new CustomAdaptor, 
        }); 
    .  .  . 
       }  
} 



Regards, 
Pavithra S. 


That was the missing hint! Thank you so much, now it works! :)


PS Pavithra Subramaniyam Syncfusion Team May 28, 2018 12:51 PM UTC

Hi Marco, 

Thanks for you update. 

We are glad to hear that the provided solution helped you. 

Please contact us if you have any queries. 

Regards, 
Pavithra S. 



SK Satheesh Kumar November 17, 2023 05:25 AM UTC

Hi


I am using react with msal and i have similar scenario and beforesend is working fine. But when token expires, i need to fetch new token and if that fails too, i need to logout. How to achieve this? And also will this beforesend wait till new token is fetched. Please help me on these.



VS Vikram Sundararajan Syncfusion Team December 27, 2023 12:02 PM UTC

Hi Satheesh Kumar,


Greetings from Syncfusion support,


Based on your query when token expires, need to fetch new token and also will this beforesend wait till new token is fetched. In response to your query, we would like to clarify that our current architecture utilizes synchronous methods for "processQuery" and "beforeSend." Unfortunately, this means that it is not feasible for these methods to wait for the generation of a new token through an asynchronous process.


Please let us know if you need any further assistance.


Regards,

Vikram S


Loader.
Up arrow icon