GPT-3 can really code

After struggling for hours to write a Firebase Function that would proxy GET requests to another server, and all the noise that GPT has been generating, I tried to make it come up with the same code.

Results

Amazingly, it was able to come up with nice initial versions. But even more than that, it was able to tweak the code according to my prompts. Essentially it was able to produce the same code I ended up with in a fraction of the time. You can see my manual struggle to get it to work prior to trying out GPT-3:

  1. https://www.wafrat.com/using-fetch-in-firebase-functions-in-typescript/
  2. https://www.wafrat.com/enabling-cors-in-firebase-functions/

Chat

how do i make a get request in nodejs?

To make a GET request in Node.js, you can use the built-in HTTP or HTTPS modules. Here's an example using the HTTP module:

const http = require('http');

http.get('http://example.com/', (res) => {
  console.log(`Status code: ${res.statusCode}`);

  res.on('data', (chunk) => {
    console.log(`Received data: ${chunk}`);
  });

  res.on('end', () => {
    console.log('No more data');
  });
}).on('error', (err) => {
  console.error(`Error: ${err}`);
});

In the above example, we make a GET request to http://example.com/ using the http.get() method. The callback function is called when the response is received. We log the status code of the response and then use the data event to log the response data as it comes in. Finally, we use the end event to log that all the data has been received. The error event is used to handle any errors that may occur during the request.

My thoughts: glad it used the built-in http module instead of some npm package.
New prompt: write a firebase function that streams a get request

To stream a GET request using a Firebase function, you can use the Firebase Realtime Database and the request module. Here's an example:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const request = require('request');

admin.initializeApp();

exports.streamRequest = functions.https.onRequest((req, res) => {
  const ref = admin.database().ref('/stream'); // create a reference to a database node

  request.get('http://example.com/stream') // make the GET request
    .on('data', (data) => {
      ref.push(data); // push the data to the database node
    })
    .on('error', (err) => {
      console.error(err);
      res.status(500).send('Error');
    })
    .on('end', () => {
      res.send('Stream ended'); // send a response when the stream ends
    });
});

In this example, we use the functions.https.onRequest() method to create an HTTP function that will handle incoming requests. When the function is called, we create a reference to a database node using admin.database().ref(). Then, we make a GET request using the request module and listen for the 'data' event. When data is received, we push it to the database node using ref.push(). If there's an error, we log it and send a 500 response. When the stream ends, we send a response indicating that the stream has ended.

Note: You'll need to install the firebase-admin and request modules using npm install firebase-admin request in your Firebase Functions directory before running this code.

My thoughts: not quite what I asked for. I don't want to use a Realtime Database.
New prompt:write a firebase function that streams the result of a get request. it should start with `functions.https.onRequest`

Sure! Here's an example Firebase Cloud Function that streams the result of a GET request using functions.https.onRequest:

const functions = require('firebase-functions');
const request = require('request');

exports.streamGetRequest = functions.https.onRequest((req, res) => {
  const stream = request.get('http://example.com/stream');

  res.setHeader('Content-Type', 'text/plain');
  stream.pipe(res);

  stream.on('error', (err) => {
    console.error(err);
    res.status(500).send('Error');
  });
});

In this example, we use functions.https.onRequest to create an HTTP function that will handle incoming requests. When the function is called, we create a stream variable by making a GET request using the request module's get method. Then, we set the response headers using res.setHeader to indicate that we're sending plain text data. We pipe the stream to the response using stream.pipe(res), which automatically sends the data as it's received. Finally, we handle any errors by logging them and sending a 500 response.

Note that you'll need to install the request module using npm install request in your Firebase Functions directory before running this code. Additionally, make sure to replace http://example.com/stream with the actual URL you want to stream data from.

My thoughts: glad that it understood my request to use onRequest instead of the Realtime Database. Also, very nice that it thought to stream the result of request.get to res.
request has been discontinued since 2019. can you fix it?

Yes, you're right. The request module has been deprecated since 2019 and is no longer recommended. Instead, you can use the node-fetch module, which provides similar functionality and is actively maintained. Here's an updated version of the Firebase function that uses node-fetch:

const functions = require('firebase-functions');
const fetch = require('node-fetch');

exports.streamGetRequest = functions.https.onRequest((req, res) => {
  const url = 'http://example.com/stream';

  fetch(url)
    .then((response) => {
      res.setHeader('Content-Type', 'text/plain');
      response.body.pipe(res);
    })
    .catch((err) => {
      console.error(err);
      res.status(500).send('Error');
    });
});

In this updated version, we use node-fetch to make the GET request. We set the Content-Type header to 'text/plain' to indicate that we're sending plain text data. Then, we pipe the response body directly to the response using response.body.pipe(res). Finally, we handle any errors using a catch block and send a 500 response if an error occurs.

Make sure to install the node-fetch module using npm install node-fetch in your Firebase Functions directory before running this code. Also, replace the url variable with the actual URL you want to stream data from.

My thoughts: it really thought like a human and went for the next alternative, node-fetch, just as I had read in StackOverflow posts. I want to make it use the built-in http and https modules again.
New prompt: can you do it without using npm packages?

Yes, you can use the built-in http module in Node.js to make the GET request without using any external packages. Here's an example Firebase function that uses http to stream the result of a GET request:

const functions = require('firebase-functions');
const http = require('http');

exports.streamGetRequest = functions.https.onRequest((req, res) => {
  const options = {
    hostname: 'example.com',
    path: '/stream',
    method: 'GET'
  };

  const request = http.request(options, (response) => {
    res.setHeader('Content-Type', 'text/plain');
    response.pipe(res);
  });

  request.on('error', (err) => {
    console.error(err);
    res.status(500).send('Error');
  });

  request.end();
});

In this example, we use the http module's request method to make the GET request. We set the hostname, path, and method options to the appropriate values for the URL we want to stream data from. Then, we set the Content-Type header to 'text/plain' to indicate that we're sending plain text data. We pipe the response directly to the response using response.pipe(res). Finally, we handle any errors using a request.on('error') handler and send a 500 response if an error occurs.

Note that you don't need to install any external packages to use this code. Simply copy and paste it into your Firebase function. Also, replace 'example.com' and '/stream' with the actual URL and path you want to stream data from.

New prompt: fix the content-type to return json

Sure! To fix the Content-Type header to return JSON data, you can change the header value to 'application/json'. Here's an updated version of the Firebase function with the Content-Type header set to 'application/json':

const functions = require('firebase-functions');
const http = require('http');

exports.streamGetRequest = functions.https.onRequest((req, res) => {
  const options = {
    hostname: 'example.com',
    path: '/stream',
    method: 'GET'
  };

  const request = http.request(options, (response) => {
    res.setHeader('Content-Type', 'application/json');
    response.pipe(res);
  });

  request.on('error', (err) => {
    console.error(err);
    res.status(500).send('Error');
  });

  request.end();
});

In this updated version, we changed the Content-Type header to 'application/json' to indicate that we're returning JSON data. The rest of the code is the same as before.

Make sure to replace 'example.com' and '/stream' with the actual URL and path you want to stream JSON data from.

My thoughts: this way of requiring npm packages does not work with Firebase Functions. Let's see if it comes up with the fix to use import instead.
New prompt: i am getting this error: "Require statement not part of import statement  @typescript-eslint/no-var-requires". can you fix it?

Yes, this error occurs when you're using a require statement to import a module in TypeScript, which is not recommended. To fix this error, you can use an import statement instead of require. Here's an updated version of the Firebase function that uses import statements:

import * as functions from 'firebase-functions';
import * as http from 'http';

export const streamGetRequest = functions.https.onRequest((req, res) => {
  const options: http.RequestOptions = {
    hostname: 'example.com',
    path: '/stream',
    method: 'GET'
  };

  const request = http.request(options, (response) => {
    res.setHeader('Content-Type', 'application/json');
    response.pipe(res);
  });

  request.on('error', (err) => {
    console.error(err);
    res.status(500).send('Error');
  });

  request.end();
});

In this updated version, we use import statements to import the firebase-functions and http modules. We also define the options object with an explicit type of http.RequestOptions. The rest of the code is the same as before.

Make sure to install the required packages (firebase-functions and @types/node) before running this code. You can install them using npm install firebase-functions @types/node.

My thoughts: we're getting there! Now let's see if it can do CORS.
New prompt: can you enable cors to allow the domain https://my-domain.com?

Yes, you can enable CORS to allow a specific domain (e.g. https://my-domain.com) to make requests to your Firebase function. Here's an updated version of the Firebase function that enables CORS for https://my-domain.com:

import * as functions from 'firebase-functions';
import * as http from 'http';

export const streamGetRequest = functions.https.onRequest((req, res) => {
  // Set CORS headers
  res.set('Access-Control-Allow-Origin', 'https://my-domain.com');
  res.set('Access-Control-Allow-Methods', 'GET');

  // Handle preflight request
  if (req.method === 'OPTIONS') {
    res.set('Access-Control-Allow-Headers', 'Content-Type');
    res.status(204).send('');
    return;
  }

  const options: http.RequestOptions = {
    hostname: 'example.com',
    path: '/stream',
    method: 'GET'
  };

  const request = http.request(options, (response) => {
    res.setHeader('Content-Type', 'application/json');
    response.pipe(res);
  });

  request.on('error', (err) => {
    console.error(err);
    res.status(500).send('Error');
  });

  request.end();
});

In this updated version, we first set the CORS headers using res.set() to allow requests from https://my-domain.com. We also specify that only GET requests are allowed.

We then handle preflight requests by checking if the incoming request method is OPTIONS. If it is, we set the Access-Control-Allow-Headers header to allow the Content-Type header and return a 204 response with an empty body.

The rest of the code is the same as before.

Make sure to replace https://my-domain.com with the actual domain you want to allow requests from.

My thoughts: it switched to Typescript. Funny, I was going to ask it to use Typescript eventually.
New prompt: can you add the following key-values to the header when making a request to example.com: app-id: "abc" and app-id-key: "12345"?

Yes, you can add the app-id and app-id-key headers to the HTTP request by setting the corresponding properties in the options.headers object. Here's an updated version of the Firebase function that adds these headers to the HTTP request:

import * as functions from 'firebase-functions';
import * as http from 'http';

export const streamGetRequest = functions.https.onRequest((req, res) => {
  // Set CORS headers
  res.set('Access-Control-Allow-Origin', 'https://my-domain.com');
  res.set('Access-Control-Allow-Methods', 'GET');

  // Handle preflight request
  if (req.method === 'OPTIONS') {
    res.set('Access-Control-Allow-Headers', 'Content-Type');
    res.status(204).send('');
    return;
  }

  const options: http.RequestOptions = {
    hostname: 'example.com',
    path: '/stream',
    method: 'GET',
    headers: {
      'app-id': 'abc',
      'app-id-key': '12345'
    }
  };

  const request = http.request(options, (response) => {
    res.setHeader('Content-Type', 'application/json');
    response.pipe(res);
  });

  request.on('error', (err) => {
    console.error(err);
    res.status(500).send('Error');
  });

  request.end();
});

In this updated version, we add a headers property to the options object and set its value to an object with app-id and app-id-key properties. These properties will be added to the HTTP request headers.

The rest of the code is the same as before.

Make sure to replace 'abc' and '12345' with the actual values for app-id and app-id-key.

New prompt: can you modify this code to make a https request to example.com instead of http?

Yes, you can modify the code to make an HTTPS request to example.com instead of an HTTP request by changing the protocol in the options object from http to https. Here's the updated Firebase function:

import * as functions from 'firebase-functions';
import * as https from 'https';

export const streamGetRequest = functions.https.onRequest((req, res) => {
  // Set CORS headers
  res.set('Access-Control-Allow-Origin', 'https://my-domain.com');
  res.set('Access-Control-Allow-Methods', 'GET');

  // Handle preflight request
  if (req.method === 'OPTIONS') {
    res.set('Access-Control-Allow-Headers', 'Content-Type');
    res.status(204).send('');
    return;
  }

  const options: https.RequestOptions = {
    hostname: 'example.com',
    path: '/stream',
    method: 'GET',
    headers: {
      'app-id': 'abc',
      'app-id-key': '12345'
    }
  };

  const request = https.request(options, (response) => {
    res.setHeader('Content-Type', 'application/json');
    response.pipe(res);
  });

  request.on('error', (err) => {
    console.error(err);
    res.status(500).send('Error');
  });

  request.end();
});

In this updated version, we import the https module instead of the http module. We also change the options object type to https.RequestOptions.

We then modify the options object by changing the protocol to https.

The rest of the code is the same as before.

Make sure to replace 'example.com', 'abc' and '12345' with the actual values for the hostname, app-id and app-id-key.

Conclusion

GPT-3 can't write everything perfectly on the first try, but it is incredibly good at tweaking the code until you get what you want. I will definitely try using it more for tasks that I am not familar with. Btw, this does not mean that our skills are useless. It still takes judgment to know what you are looking for and coming up with the prompts to nudge it to the correct path. For example, I had struggled for a long time with request and node-fetch  and it's only after reading lots of documentation that I realized I should use the standalone https modules.