1

I have an application that calls an api that returns files and compresses them into a zip file.

I have created my own service and it works perfectly.

return this.http.get(this.rootUrl + '/api/Files/DownloadFile?files=' + fileSelected + '&user=' + user, { responseType: 'blob' as 'json' }); // working ok

Here the api response is a blob object as it must be.

But when I try to do the same thing using a swagger generated service, it doesn't work anymore.

let req = new HttpRequest<any>(
    'GET',
    this.rootUrl + `/api/Files/DownloadFile`, 
    __body, 
    {
    headers: __headers,
    params: __params,
    responseType: 'text'
}
); // not working ok

The service returns me null, however in chrome inspector, in the response to the api call, it shows strange characters.

this.filesService.DownloadFile({"files": ids, "user": this.user}).subscribe(
    data => {
        console.log(data); // data value is null but in the response I see strange characters
    },
    err => { 
        console.log(err);
    }
);

This is normal, because the responseType of the swagger service is "text", I have tried to manually change the contentType to "blob" (swagger specifications) or "blob as json" (angular 5), but it didn't working ok.

Is it possible to solve it from Angular using the service generated by swagger or do I have to touch the API? Thank you

Eladerezador
  • 1,277
  • 7
  • 25
  • 48

1 Answers1

1

You can use a HttpInterceptor to correct the responseType of your request. E.g. for service functions returning media type 'application/octet-stream':

import {Injectable} from '@angular/core';
import {
  HttpEvent, HttpInterceptor, HttpHandler, HttpRequest
} from '@angular/common/http';

import {Observable} from 'rxjs';

@Injectable()
export class FileDownloadHttpInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler):
    Observable<HttpEvent<any>> {
    if (req.headers.get('Accept') === 'application/octet-stream') {
      // @ts-ignore: ignore that responseType is read only
      req.responseType = 'blob';
    }
    return next.handle(req);
  }
}

Then provide the interceptor in the appropriate module, e.g. app.module.ts:

providers: [{
      provide: HTTP_INTERCEPTORS, useClass: FileDownloadHttpInterceptor, multi: true
    }]

The final steps depend on what your service exactly returns. For me it was sufficient to call window.open(response.url); for the HttpResponse from the service, but perhaps you have to convert the response to a blob and the blob to an URL first, see How do I download a file with Angular2 or greater.

P.S.: It's surely not the best coding style to manipulate requests with HttpInterceptors. A solution on the service generation side would be preferable. But I found no possibility to specify a responseType in den OpenApi description of the service, and the generated service was not smart enough to change its default json response type according to the declared return type of the service (or I was not smart enough to configure the generator appropriately).

user11883568
  • 309
  • 3
  • 6