Backend images are failing to load

I'm facing an issue where the image I send from a nestjs backend to an angular frontend isn't displaying in the browser.

https://i.sstatic.net/nicu4.png

Here's how it works: I make a request from the frontend to the backend with the file path on the server (e.g., "C:\MyFolder\MyFile.png"). The backend reads the image and sends a stream back to the frontend. The frontend then converts the blob into an image and sets the src attribute of an img element to display the image.

Backend

Below is the code snippet from the controller:

@HttpCode(201)
@Get(':imageUrl')
@Header('Content-Type', 'image/png')
getFile(@Param('imageUrl')imageUrl: string) {
    imageUrl = atob(imageUrl);
    return fs.createReadStream(imageUrl);
}

Frontend

Here is the TypeScript code for the language selector:

currentLanguage: ApplicationLanguage;
availableLanguages: ApplicationLanguage[];

constructor(private readonly _languageProvider: CultureProviderService,
          private readonly _imageLoader: ImageService) {
    // Code here...
}
ngOnInit(): void {
    // Code here...
}
// More code snippets here...

The service used to fetch the image is as follows:

constructor(private readonly _http: HttpClient,
          private domSanitizer: DomSanitizer) { }
          
// Code for getImage() and createImageFromBlob() methods

The HTML section:

<div>
  <mat-selection-list (selectionChange)="changeLanguage($event)"
                      [multiple]="false">
    <mat-list-option  *ngFor="let language of availableLanguages"
                      [value]="language"  [selected] ="isSelected(language)">
      <img [src]="language.image" height="70px" width="70px" alt="Flag">
    </mat-list-option>
  </mat-selection-list>
</div>

If you see any issues or have suggestions, please let me know!

Edit:

The solution based on the accepted answer

To resolve the issue, I needed to upgrade the nestjs version to v8+. I encountered some challenges during the update process but managed to get it working by creating a new nestjs project using CLI v8+.

I also updated the controller's code to utilize StreamableFile as per the recommended solution:

@HttpCode(201)
@Get(':imageUrl')
@Header('Content-Type', 'image/png')
getFile(@Param('imageUrl')imageUrl: string): StreamableFile {
  imageUrl = Buffer.from(imageUrl, 'base64').toString();

  const file = createReadStream(imageUrl);
  return new StreamableFile(file);
}

For more information, check out the official resource: https://docs.nestjs.com/techniques/streaming-files

Answer №1

To send a stream back as a response, you can implement it like this:

@HttpCode(201)
@Get(':imageUrl')
@Header('Content-Type', 'image/png')
getFile(@Param('imageUrl')imageUrl: string, @Res() res: e.Response) {
    imageUrl = atob(imageUrl);
    return fs.createReadStream(imageUrl).pipe(res);
}

If you're using Nest version 8, you have the option to utilize StreamableFile and your implementation can look like this:

@HttpCode(201)
@Get(':imageUrl')
@Header('Content-Type', 'image/png')
getFile(@Param('imageUrl')imageUrl: string, @Res() res: e.Response) {
    imageUrl = atob(imageUrl);
    return new StreamableFile(fs.createReadStream(imageUrl));

Nest will take care of invoking .pipe(res) for you in the background.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having difficulty retrieving the file from Google Drive through googleapis

I'm currently attempting to retrieve a file from Google Drive using the Googleapis V3, but I keep encountering an error message stating: 'Property 'on' does not exist on type 'GaxiosPromise<Schema$File>'. Below is the c ...

Angular 4 provides the capability to reset a radio group that has been dynamically generated within a table

I am facing an issue with a dynamically created radio group inside a table in my component. I am using ngFor to generate the radio buttons, and there is a clear button outside the ngFor that should reset the radio group when clicked. However, my current im ...

I'm having trouble establishing a connection with the Appwrite platform

Encountered an issue while trying to connect to appwrite. The specific error message is: Uncaught (in promise) TypeError: Failed to construct 'URL': Invalid URL at Account.<anonymous> (appwrite.js?v=d683b3eb:932:19) at Generator.nex ...

Using Angular NgUpgrade to inject an AngularJS service into an Angular service results in an error message stating: Unhandled Promise rejection: Cannot read property 'get' of undefined; Zone:

I have noticed several similar issues on this platform, but none of the solutions seem to work for me. My understanding is that because our Ng2App is bootstrapped first, it does not have a reference to $injector yet. Consequently, when I attempt to use it ...

Tips for utilizing the "this" keyword in TypeScript

As a newcomer to TypeScript, I am seeking assistance on how to access the login service within the authenticate function. Despite using the 'this' keyword to retrieve the login service, it seems ineffective. Additionally, I find myself puzzled by ...

Creating Personalized Validators for Angular Version 5 Reactive Forms

I am struggling to create a custom validator for my Angular v5 application. I followed the documentation for a basic password match example in the Docs, but it's not working as expected. this.personalInfoForm = _fb.group({ 'name': [null,V ...

Using Angular 4's Renderer2 to handle dynamic element IDs

Could you please advise on how to retrieve a dynamic id from the component (ts) file using the format below? Note: My goal is to scroll the content to the specific dynamic item when a user clicks a button (in this case, it's an item in a Bar chart). ...

Is it possible to substitute a name for an ID in a request?

Currently, I am following a tutorial on angular.io at https://angular.io/tutorial/toh-pt6#get-hero-by-id. It made me think if there is a way to use names instead of ids to send requests or is it hardcoded that only numbers can be used as ids? getHero(id ...

Trigger the D3 component to re-render in React after a state change occurs in the parent component

My React project consists of two components written in TypeScript. The first component contains menus, and I am using conditional rendering to display different content based on user selection. <Menu.Item name="graph" active={activeItem ...

The `NgForOf` directive is used to iterate over lists of strings or string arrays within a given `NgIterable` of strings or string

Here is a data type example: export interface TYPE_A { valueType: TYPE_A_VALUE_TYPES; value: string | string[]; } export enum TYPE_A_VALUE_TYPES { singleValue = "singleValue", multiValue = "multiValue", } In my component, I am ...

Here is a unique rewrite: "Strategies for accessing interface-defined fields instead of mongoose schema-defined fields

Is there a way to modify my code to return "id" instead of "_id" and without "__v" to the client using express, mongoose, and TypeScript? Code snippet: Interface: export default interface Domain { name: string; objects: DomainObject[] } Creation Int ...

What could be the reason why my focus and blur event listener is not being activated?

It seems like everything is in order here, but for some reason, the event just won't fire... const element = (this.agGridElm.nativeElement as HTMLElement); element.addEventListener('focus', (focusEvent: FocusEvent) => { element.classLi ...

How should one properly format an array of objects with elements that are different types of variations?

I am currently developing a versatile sorting module using TypeScript. This module will take in an array of data objects, along with a list of keys to sort by. Once the sorting process is complete, the array will be sorted based on the specified keys. To ...

Ways to display an icon in Angular 10 only when it is hovered over

Just getting started with Angular and still learning the concepts. Trying to figure out how to show an icon only when it's hovered over. Can anyone assist me? Sorry, can't share the code because of company rules. The icons are for sorting and ...

What is the method for obtaining a date in the format of 2018-05-23T23:00:00.000+00:00?

Recently, I've been attempting to filter data based on dates in my database. The format in which the dates are saved is as follows: 2018-05-23T23:00:00.000+00:00 This was my initial approach: router.get('/byDate', function (req, res) { ...

Leveraging the power of mat-option and mat-radio-button within a mat-select or mat-selection-list

I'm currently working on a unique form element that combines checkboxes and radio buttons to create a multi-level selection feature. For instance, you can use it to configure properties for a car where a radio option (Digital or FM) is dependent on t ...

NestJS Exporting: Establishing a connection for PostgreSQL multi tenancy

I have been working on implementing a multi tenancy architecture using postgres. The functionality is all in place within the tenant service, but now I need to import this connection into a different module called shops. Can anyone provide guidance on how ...

Tips for calculating the total count of a specific field within a JSON array with TypeScript

I have a JSON array. "user": { "value": [ { "customerNo": "1234" }, { "customerNo": "abcd" }, { "c ...

The httpClient post request does not successfully trigger in an angular event when the windows.unload event is activated

Is there a way to send a post request from my client to the server when the user closes the tab or browser window? I have tried using the 'windows.unload'or 'windows.beforeunload' event, but the call doesn't seem to be successful a ...

Identifying modifications within the @Input property in Angular 4

Can someone clarify how to detect changes in an @Input property within a component, rather than just when passed from its parent? I haven't found a clear answer to this yet. Thank you! ...