Stream Response into HTTP Response
Asked Answered
C

2

18

I have an API that is trying to make an HTTP request to an API that streams and image back to the me, then either stream that image back to the client making the request to me or wait until the image has been streamed to me and send it all at once.

I am using Express and request-promise.

Here's a shortened version of my code.

const express = require('express');
const router = express.Router();
const request = require('request-promise');

const imgFunc = async () => {
  try {
    const response = await request.get({
      method: 'GET',
      uri: `http://localhost:8080`,
    });
    return response;
  } catch(err) {
    console.log(err);
  }
};

router.get('/', async function(req, res, next) {
  try {
    const response = await imgFunc();
    return res.send(response);
  } catch (err) {
    console.log(err);
  }
});

module.exports = router;

The image that I get back is just what I assume is the binary data and I don't know if I need to do something at the request-promise level to make that right or when I send it back to the client.

The server that I have running at localhost:8080 mimics the actual server that I will be hitting when this is all said and done.

Chiropodist answered 10/9, 2017 at 21:28 Comment(0)
C
26

You could pipe the streams directly rather than using request-promise.

const express = require('express');
const router = express.Router();
const https = require('https');

router.get('/', function(req, res) {
    const url = 'https://www.gravatar.com/avatar/2ea70f0c2a432ffbb9e5875039645b39?s=32&d=identicon&r=PG&f=1';

    const request = https.get(url, function(response) {
        const contentType = response.headers['content-type'];

        console.log(contentType);

        res.setHeader('Content-Type', contentType);

        response.pipe(res);
    });

    request.on('error', function(e){
        console.error(e);
    });
});

module.exports = router;

Or using the request library on which request-promise is based:

const express = require('express');
const router = express.Router();
const request = require('request');

router.get('/', function(req, res) {
    const url = 'https://www.gravatar.com/avatar/2ea70f0c2a432ffbb9e5875039645b39?s=32&d=identicon&r=PG&f=1';

    request.get(url).pipe(res);
});

module.exports = router;
Canossa answered 10/9, 2017 at 22:31 Comment(2)
The second method works great even with request-promise. My only hand up with it is that I have to have the logic of making the request in the router itself and not in a separate function that returns the image like I had before.Chiropodist
Additionally, this does not allow us to "return" the res, which is an idiom that is typically followed. I don't think that's a huge deal, but it's worth noting.Chiropodist
A
2

you could pipe the streams directly through axios

const express = require('express');
const router = express.Router();
const axios = require("axios");

router.get('/', function(req, res) {
    const link = 'https://app.idesk360.com/media/logos/iDeskLoginTxt.png';
    const arrayBuffer = await axios.get(link, {responseType: 'stream'});
    const contentType = arrayBuffer.headers["content-type"];
    res.setHeader('content-type', contentType);
    arrayBuffer.data.pipe(res);
});

module.exports = router;
Acceptant answered 30/3, 2022 at 16:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.