iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🐣

Fetching from Node.js/Frontend to GAS

に公開

Posting to GAS from a Nuxt App

I'm a non-programmer who started programming with GAS (Google Apps Script), but lately, I've been studying Nuxt.js!

One of the great things about GAS is that you can use a published web app as an API server to easily control Google services like Sheets, Drive, and Gmail!

I ran into a bit of a snag, so I'm summarizing it here as a note to self.

Axios is a bit hit-or-miss

When setting up a Nuxt app, you're asked whether to include the axios module. I chose "Okay, axios then!", and prepared the GAS side as well.
Immediately I tried to run it, but it throws a CORS error when called from the backend...
There aren't even any logs in the GAS execution history.

Apparently, as mentioned in the reference articles, XmlHttpRequest doesn't seem to play well here.

api/gas.js This doesn't work
import axios from 'axios';
const post = async (postData = {}) {
  const options = {
    'Content-Type': "application/json"
  }
  try {
    const res = await axios(GAS_ENDPOINT_URL, JSON.stringify(postData), options);
    const json = await res.text();
    return JSON.parse(json);
  } catch (e) {
    console.error(e.stack);
    return null;
  }
}
export default post;
main.gs GAS side
function doPost(e) {
  return ContentService.createTextOutput().setMimeType(ContentService.MimeType.JSON).setContent(JSON.stringify({ result: 'ok!', e }));
}

From the frontend, it works if you specify the content-type as a form format.

pages/index.vue
// JS part only
export default {
  methods: {
    async post(postData = {}) {
      const options = {
        'content-type': 'x-www-form-urlencoded',
        mode: 'no-cors'
      }
      try {
        const res = await this.$axios.post(GAS_ENDPOINT_URL, postData, options);
        const json = await res.text();
        return JSON.parse(json);
      } catch (e) {
        console.error(e.stack);
        return null;
      }
    }
  }
}

node-fetch works for both frontend and backend

So I decided to try a different npm package and installed node-fetch, which is based on the Fetch API.

pages/index.vue This works
// JS part only
import fetch from 'node-fetch';
export default {
  methods: {
    async post(postData = {}) {
      const options = {
        method: "post",
        'Content-Type': "application/json",
        body: postData
      }
      try {
        const res = await fetch(GAS_ENDPOINT_URL, options);
        const json = await res.text();
        return JSON.parse(json);
      } catch (e) {
        console.log(e.stack);
        return null;
      }
    }
  }
}
api/gas.js Also works from the backend
import fetch from 'node-fetch';
const post = async (postData = {}) {
  const options = {
    method: "post",
    'Content-Type': "application/json",
    body: JSON.stringify(postData)
  }
  try {
    const res = await fetch(GAS_ENDPOINT_URL, options);
    const json = await res.text();
    return JSON.parse(json);
  } catch (e) {
    console.log(e.stack);
    return null;
  }
}
export default post;

Reference Articles

https://www.bugbugnow.net/2019/06/gasweb.html
https://knmts.com/become-engineer-31/

Discussion