jpls93
jpls93

Reputation: 614

How do I create a Node.js proxy server hosted through Firebase Cloud Functions?

I have an application which uses a YouTube API key to search for videos on YouTube and display them on my page. I've just learned that it's bad to expose any secrets to the client. So, the solution I'm considering is to have the client send requests to a Firebase cloud function instead. The cloud function will serve as the proxy where my API key will be stored instead of storing it in the client.

How do I set it up?

For starters, I tried logging the request object but I'm getting a cryptic error message.

error: SUPERVISOR clientError { Error: Parse Error bytesParsed: 0, code: 'HPE_INVALID_METHOD' } connecting=false, _hadError=false, bytesRead=193, , fd=
-1, reading=true, $ref=$, onread=function onread(nread, buffer) {

Here's the GET request sent by the client that produced the error message above

https://localhost:5000/jpls-youtube-viewer/us-central1/helloWorld?part=snippet&type=video&q=Linkin+Park

Here's the repo of my application: https://github.com/jpls93/jpls-youtube-viewer

And here's the hosted site: https://jpls-youtube-viewer.firebaseapp.com/

Upvotes: 9

Views: 8069

Answers (2)

const https = require('https');
const buffer = require('buffer');

exports.proxyURL = functions.https.onRequest(async (req, res) => {

const url = req.query.url;  
await https.get(url, (resp) => {   

let data = '';
// A chunk of data has been received.
resp.on('data', (chunk) => {

  let ctype = resp.headers["content-type"];
  if (ctype.includes("charset=ISO-8859-1"))
  {
    const latin1Buffer = buffer.transcode(Buffer.from(chunk), "latin1", "utf8");      
    data += latin1Buffer.toString("utf8");
  }else{
    data += chunk;
  }            
});

// The whole response has been received. Print out the result.
resp.on('end', () => {          
  res.contentType('application/xml; charset=UTF-8');      
  res.write(data);
  return res.status(200).end();
});

}).on("error", (err) => {
console.log("Error: " + err.message);
return res.status(500).end();
});  
});

Upvotes: 0

jpls93
jpls93

Reputation: 614

I solved it by pointing the client request to my Firebase database URL then I had the Firebase database URL do the request to the YouTube REST API URL and resolve the response to my client. I had an issue with CORS, but that was simply fixed by allowing access-control-origin/methods

exports.helloWorld = functions.https.onRequest((request, response) => {
  var term = request.query.q;
  // See https://howtofirebase.com/firebase-cloud-functions-753935e80323
  // why we're requiring it inside the function
  var YT_URL = "https://www.googleapis.com/youtube/v3/search";
  const axios = require("axios");
  axios
    .get(YT_URL, {
      params: {
        part: "snippet",
        type: "video",
        key: require("./secret"),
        q: term
      }
    })
    .then(YouTubeData => {
      response.set("Access-Control-Allow-Origin", "*");
      response.set("Access-Control-Allow-Methods", "GET, POST");
      response.status(200).send(YouTubeData.data.items);
    })
    .catch(err => console.error(err));
});

Upvotes: 4

Related Questions