An API built with Mongoose, Express, and Node.js is currently only able to send a single image

I have a buffer array that needs to be converted into images and sent to the user. The issue is that the current code only sends one image:

const express = require("express");
const asyncHandler = require("express-async-handler");
const Image = require('../models/Image');
const router = express.Router();
const multer = require('multer');
const sharp = require('sharp');

router.get("/", asyncHandler(async (req, res) => {
  const imagesInfo = await Image.find();
  const imagesBuffers = imagesInfo.map((img) => img.data);

  const promises = imagesBuffers.map((buffer) =>
    sharp(buffer).toFormat('jpeg').toBuffer()
  );
  Promise.all(promises)
    .then((outputBuffers) => {
      res.contentType('image/jpeg');
      outputBuffers.forEach((outputBuffer) => {
        res.write(outputBuffer, 'binary');
      });

      res.end();
    })
    .catch((err) => {
      console.error('Error:', err);
      res.status(500).send('Error.');
    });
}));
module.exports = router;

../models/Image refers to:

const mongoose = require("mongoose");
const ImageSchema = new mongoose.Schema({
  filename: { type: String, },
  data: { type: Buffer, },
}, { timestamps: true });
const Image = mongoose.model("Image", ImageSchema);
module.exports = Image;

Is there a way to modify it so that it can send all available images instead of just one?

Answer №1

Your current implementation faces an issue as it tries to send multiple images in a single HTTP response, which is not directly supported by HTTP standards. Each HTTP response should be intended for a single resource only. Fortunately, there are several ways to work around this limitation for your specific use case.

Encode Images as Base64

To address this issue, the server can transmit the images back to the client as an array of base64 strings. Here's how:

router.get("/", asyncHandler(async (req, res) => {
  const imagesInfo = await Image.find();
  
  const promises = imagesInfo.map((img) => 
    sharp(img.data).toFormat('jpeg').toBuffer()
  );

  Promise.all(promises)
    .then((outputBuffers) => {
      const base64Images = outputBuffers.map(buffer => buffer.toString('base64'));
      res.json(base64Images);
    })
    .catch((err) => {
      console.error('Error:', err);
      res.status(500).send('Error.');
    });
}));

Below is an example code snippet demonstrating how the client side can handle the encoded image responses:

<div id="container"></div>

<script>
  fetch('http://yourserver.com/')
    .then(response => response.json())
    .then(images => {
      const container = document.getElementById('container');
      
      images.forEach(base64Image => {
        const img = document.createElement('img');
        img.src = 'data:image/jpeg;base64,' + base64Image;
        container.appendChild(img);
      });
    })
    .catch(error => console.error('Error:', error));
</script>

However, it's important to note that encoding images as base64 will increase data size by approximately 33%, potentially impacting performance if speed is crucial for your project.

Send Image URLs Instead

Alternatively, you can choose to share the image URLs with the client instead. This method typically serves the same purpose depending on the client's objectives. Since each image likely has a unique file name, you could follow this approach:

router.get("/", asyncHandler(async (req, res) => {
  const imagesInfo = await Image.find();
  const imageUrls = imagesInfo.map((img) => `http://yourserver.com/images/${img.filename}`);
  res.json(imageUrls);
}));

// Endpoint to serve an individual image
router.get("/images/:filename", asyncHandler(async (req, res) => {
  try {
    const filename = req.params.filename;
    const imageInfo = await Image.findOne({ filename: filename });

    if (imageInfo) {
      const buffer = imageInfo.data;
      const image = await sharp(buffer).toFormat('jpeg').toBuffer();
      res.contentType('image/jpeg');
      res.send(image);
    } else {
      res.status(404).send('Image not found.');
    }
  } catch (err) {
    console.error('Error:', err);
    res.status(500).send('Error.');
  }
}));

Keep in mind that if you require raw image data for any reason, this method might not suit your needs out of the box, as you would have to retrieve the raw data individually from each URL returned in the initial request.

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

Develop an interactive single-page scrolling system for seamless navigation between points

Creating a navigation that scrolls to the selected element when clicking on an <a> tag is my current project. I want it to animate smoothly during the transition. The navigation should go from: <a href="#Home">Home</a> To: <div id= ...

Retrieve the file from Amazon S3 and download it

I'm having an issue with downloading a file from a directory outside of the root. Whenever I try, it defaults to looking in the root directory. I need users to be able to download these files on my site. The file was initially uploaded to Amazon S3 a ...

My ng-view html is unexpectedly displaying as plain string. What steps should I take to resolve this issue?

Why is my ng-view HTML displaying as plain text? How can I resolve this issue? I have encountered an error, here is the screenshot for reference: Unfortunately, I am unable to upload images at the moment. ...

Braintree drop-in feature now allows for automatic disabling of the submit button while the transaction

I've been struggling with a seemingly simple task that I just can't seem to figure out. I'm using Braintree's dropin UI and I have a submit button that I need to disable while the processing is happening, but I can't seem to find t ...

Using Node.js and Express to serve index.html rather than a static file

Recently, I started developing a node.js app with express and Angular on cloud9. Everything was smooth sailing until I deployed the app on my EC2 instance. Now, whenever I try to access my static files, Node always serves up the index.html instead. In the ...

Tips for Maintaining the Execution of a JavaScript Function Within a Class until the Browser Window is Closed (Web Development)

The title might be a little confusing, so let me clarify here: I have implemented a popup that appears in the bottom right corner of a specific page on my website. The popup is working as intended (it shows up when the page is initially opened and can be ...

a commerce website powered by a MEAN stack

I've encountered a challenge while working on my e-commerce project. When a customer selects products to purchase, I store them in their cart. However, upon validation, I am facing difficulty updating the total quantity of the purchased products. My ...

Troubleshooting Google Authorization Issue in Angular 17: How to Fix the Error TS2304: 'google' Not Found in Angular 17

I am encountering an issue while attempting to integrate Google Auth into my Angular(+Express) application using the Google Identity Services library. Despite following the instructions provided in the Google tutorial, I am facing the error: "[ERROR] TS230 ...

Encountering a problem when attempting to use the 'express' module

After installing the Express framework globally, I encountered an error when trying to use it in my app. The error message is indicating that the module cannot be found. ...

Searching with jQuery UI Autocomplete

I am interested in implementing jQuery UI autocomplete to allow users to search for items on my website. I have a list of products that I want to convert into JSON data (or just include them directly in JavaScript like the jQuery UI demo does), but I&apos ...

Creating operations in Angular using the Model View Controller (MVC)

What is the procedure for performing an Add operation in MVC using Angular? var addProductModule = angular.module("addProductModule", []); addProductModule.factory("addProductService", ['$http', function ($http) { return { function savePro ...

What's the best way to set up multiple NestJS providers using information from a JSON file?

Recently diving into NestJS, I am in the process of building an application following the MVC architecture with multiple modules including: Project | +-- App.Controller +-- App.Service +-- App.Module | +-- SubModule1 | | | +-- SubModule1.C ...

When outputting the $http response in the console, Angular displays null instead of the expected result,

I have encountered a peculiar issue with my local webservice developed using Spring. Everything seems to be functioning correctly when accessing it through the browser or Postman, but for some reason, when attempting a simple GET method with Angular/Ionic, ...

What is the process for exporting/importing a variable in Node.js?

What is the correct way to export/import a variable in Node.js? I attempted to use export and import methods, but I received an error message stating that it should be a module. After changing the type to module in the JSON file, it then told me that requ ...

The Bootstrap form validation is preventing the Ajax request from functioning properly

Having successfully implemented a form with Bootstrap validation, I encountered an issue where the AJAX Post method fails to execute after validation. The catch clause does not capture any errors and only the ajax portion of the code doesn't run. Belo ...

Developing a calendar with limited availability for selecting future dates and restricting the ability to choose past dates

I am currently working on creating a calendar in Vue.js that allows users to select dates only from the current day up to the next 30 days. Dates prior to the current date are disabled, as well as dates beyond the initial 30-day period. While I have exper ...

Navigating through the sidebar on Next.js

I am currently exploring how to utilize next.js routes for dynamically populating a sidebar component with route instructions. The goal is to have the main div display the relevant component when a sidebar option is clicked. While I've come across tu ...

Activate Pop-up for a single instance on BigCommerce

After researching and adding my own code, I am still struggling to get this question answered correctly. Here are the key points I am trying to achieve: 1. Automatically open a popup when the homepage loads. 2. Ensure that the popup is centered on all brow ...

Bring back enhanced assortment using Mongoose

I am currently working with a stack that includes nodejs, express, mongoose, and angularjs. My task involves updating a collection called Lists which contains various properties, including an array of items. The issue I am facing is that when I push a new ...

The rendering of the input dropdown control in Angular JS is experiencing difficulties

I am currently using your Angular JS Input Dropdown control, and I have followed the code example provided on your demo page in order to implement the control on a specific page of my website built with PHP Laravel. However, I have encountered an issue dur ...