Why is my code that retrieves the first H1 from a Google Doc returning 'Cannot read properties of undefined (reading 'content')' error?

This topic was automatically generated from Slack. You can find the original thread here.

I was running this code for a while and today it’s giving me errors. It’s supposed to pull the first H1 from a Google Doc and return it as a string.

import { axios } from "@pipedream/platform";

export default defineComponent({
  props: {
    google: {
      type: "app",
      app: "google",
    },
    docId: {
      type: "string",
      label: "Google Doc ID",
    },
  },
  async run({ steps, $ }) {
    const response = await axios($, {
      url: `https://docs.googleapis.com/v1/documents/${this.docId}`,
      headers: {
        Authorization: `Bearer ${this.google.$auth.oauth_access_token}`,
      },
    });

    const firstH1 = response.body.content.find(
      (element) => element.paragraph && element.paragraph.paragraphStyle.namedStyleType === "HEADING_1"
    );

    if (firstH1) {
      const h1Text = firstH1.paragraph.elements[0].textRun.content.trim();
      return h1Text;
    } else {
      console.log("No H1 found in the document");
    }
  },
});

I’m getting the following error:

Cannot read properties of undefined (reading 'content')

I know that my Google Workspace is connected properly and the ID that is passed is a working document.

I’m sorry to hear that you’re experiencing issues with your code. It seems like the error is related to accessing the content property. To address this issue, let’s add a check to ensure that response.body.content exists before trying to access its properties. Here’s the updated code: ```
import { axios } from “@pipedream/platform”; export default defineComponent({ props: { google: { type: “app”, app: “google”, }, docId: { type: “string”, label: “Google Doc ID”, }, }, async run({ steps, $ }) { const response = await axios($, { url: https://docs.googleapis.com/v1/documents/${this.docId}, headers: { Authorization: Bearer ${this.google.$auth.oauth_access_token}, }, }); if (response.body && response.body.content) { const firstH1 = response.body.content.find( (element) => element.paragraph && element.paragraph.paragraphStyle.namedStyleType === “HEADING_1” ); if (firstH1) { const h1Text = firstH1.paragraph.elements[0].textRun.content.trim(); return h1Text; } else { console.log(“No H1 found in the document”); } } else { console.log(“No content found in the response”); } }, });

I ran that code. I see received the error and I didn’t see any thing else indicating what the problem is.

I apologize for the inconvenience. Let’s add some error handling to the code to get more information about the issue. Please update your code with the following: ```
import { axios } from “@pipedream/platform”; export default defineComponent({ props: { google: { type: “app”, app: “google”, }, docId: { type: “string”, label: “Google Doc ID”, }, }, async run({ steps, $ }) { try { const response = await axios($, { url: https://docs.googleapis.com/v1/documents/${this.docId}, headers: { Authorization: Bearer ${this.google.$auth.oauth_access_token}, }, }); if (response.body && response.body.content) { const firstH1 = response.body.content.find( (element) => element.paragraph && element.paragraph.paragraphStyle.namedStyleType === “HEADING_1” ); if (firstH1) { const h1Text = firstH1.paragraph.elements[0].textRun.content.trim(); return h1Text; } else { console.log(“No H1 found in the document”); } } else { console.log(“No content found in the response”); } } catch (error) { console.error(“Error:”, error.message); console.error(“Error details:”, error.response ? error.response.data : “No additional details available”); } }, });

I received the following error:

Error: "!DOCTYPE html\n<html lang=en>\n  <meta charset=utf-8>\n  <meta name=viewport content=\"initial-scale=1, minimum-scale=1, width=device-width\">\n  <title>Error 404 (Not Found)!!1</title>\n  <style>\n    **{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}** > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}\n  </style>\n  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>\n  <p><b>404.</b> <ins>That's an error.</ins>\n  <p>The requested URL <code>/v1/documents/https://docs.google.com/document/d/1RwEFOqMmRVxk5I0p0_71ZonQEfxTqc4YBjZoFV54S5c/edit?usp=drivesdk</code> was not found on this server.  <ins>That's all we know.</ins>\n"

I have checked Google Drive and the document is there. I don’t know why Pipedream can not access it.

I’m sorry you encountered an error. It seems like you’re trying to access a Google document, but the URL in the error message is not formatted correctly. To access a Google document, you’ll need to use the Google Drive API. Here’s an example Pipedream component that retrieves the content of a Google document using the Google Drive API: import { axios } from "@pipedream/platform"; export default defineComponent({ props: { google: { type: "app", app: "google", }, documentId: { type: "string", label: "Google Document ID", }, }, async run({ steps, $ }) { const url = `https://www.googleapis.com/drive/v3/files/${this.documentId}/export`; const responseType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; return await axios($, { method: "GET", url: url, headers: { Authorization: `Bearer ${this.google.$auth.oauth_access_token}`, }, params: { mimeType: responseType, }, responseType: "arraybuffer", }); }, }); Replace documentId with the actual ID of the Google document you want to access. The ID can be found in the document URL: https://docs.google.com/document/d/<DOCUMENT_ID>/edit. Please let me know if you need further assistance or if you have any questions.

Let me explain my workflow.

  1. Getting an ASANA TASK.
  2. Looking for a custom field in the ASANA TASK which has the GOOGLE DOC URL.
  3. Running a code to strip the GOOGLE DOC ID from the GOOGLE DOC URL.
  4. Pulling the first headline from the GOOGLE DOC.
  5. Renaming the ASANA TASK NAME to the headline.
  6. Then rename the GOOGLE DOC to the name of the first headline.
    This was working just fine yesterday.

Step 4 is where the problem lies.

{"debug":{"status":404,"statusText":"Not Found","headers":{"date":"Sun, 10 Sep 2023 01:07:37 GMT","content-type":"text/html; charset=UTF-8","server":"ESF","content-length":"1671","x-xss-protection":"0","x-frame-options":"SAMEORIGIN","x-content-type-options":"nosniff","alt-svc":"h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000","x-l2-request-path":"l2-managed-5","connection":"close"},"config":{"url":"https://docs.googleapis.com/v1/documents/https://docs.google.com/document/d/1RwEFOqMmRVxk5I0p0_71ZonQEfxTqc4YBjZoFV54S5c/edit","headers":{"Accept":"application/json, text/plain, **/**","Authorization":"Bearer ya29.a0AfB_byCfU82r_xA2yVGjND2PTS1hpz56CTSdialMFwptTpsGtI3BTFXdBDtJzzFtZBJIJgc4t6GKtFstyhmrlzfUPCBpirflWc7R9daB4_1yiawXZle1vBqK4vGjUh3HXbDXc67RIfL7XxpYUTEemCGc8X-yh4UnvpyLRiQaCgYKAagSARASFQGOcNnC5I6bY8K2-JxFV-vhiJ-HxQ0174","User-Agent":"axios/0.21.4"},"params":{"usp":"drivesdk"},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"method":"get"},"data":"!DOCTYPE html\n<html lang=en>\n  <meta charset=utf-8>\n  <meta name=viewport content=\"initial-scale=1, minimum-scale=1, width=device-width\">\n  <title>Error 404 (Not Found)!!1</title>\n  <style>\n    **{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}** > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}\n  </style>\n  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>\n  <p><b>404.</b> <ins>That's an error.</ins>\n  <p>The requested URL <code>/v1/documents/https://docs.google.com/document/d/1RwEFOqMmRVxk5I0p0_71ZonQEfxTqc4YBjZoFV54S5c/edit?usp=drivesdk</code> was not found on this server.  <ins>That's all we know.</ins>\n"}}

It seems like there’s an issue with the URL you’re using to access the Google Doc. The URL should only contain the document ID, not the entire document URL. You can modify your code to extract the document ID and use it in the API request. Here’s an example of how you can do that: ```
import { axios } from “@pipedream/platform”; export default defineComponent({ props: { google: { type: “app”, app: “google”, }, docUrl: { type: “string”, label: “Google Doc URL”, }, }, async run({ steps, $ }) { // Extract the document ID from the URL const docId = this.docUrl.match(//d/(.*?)//)[1]; // Make the API request using the extracted document ID try { const response = await axios($, { url: https://docs.googleapis.com/v1/documents/${docId}, headers: { Authorization: Bearer ${this.google.$auth.oauth_access_token}, }, }); return response; } catch (error) { console.error(“Error:”, error); return error; } }, });

It seems that if I hardcode the variable in, it works.

The code where I am taking the GOOGLE DOC URL and stripping it down is:

import { axios } from "@pipedream/platform";

export default {
  name: "Extract Google Doc ID",
  description: "Extracts the Google Doc ID from a given URL",
  props: {
    url: {
      type: "string",
      label: "Google Doc URL",
    },
  },
  async run() {
    const regex = /document\/d\/([a-zA-Z0-9-_]+)/;
    const match = this.url.match(regex);
    const docId = match ? match[1] : null;
    console.log(docId);
    return docId;
  },
};

The code where I am parsing the ID is:

import { axios } from "@pipedream/platform";

export default defineComponent({
  props: {
    google: {
      type: "app",
      app: "google",
    },
    docId: {
      type: "string",
      label: "Google Doc ID",
    },
  },
  async run({ steps, $ }) {
    try {
      const response = await axios($, {
        url: `https://docs.googleapis.com/v1/documents/${this.docId}`,
        headers: {
          Authorization: `Bearer ${this.google.$auth.oauth_access_token}`,
        },
      });

      if (response.body && response.body.content) {
        const firstH1 = response.body.content.find(
          (element) => element.paragraph && element.paragraph.paragraphStyle.namedStyleType === "HEADING_1"
        );

        if (firstH1) {
          const h1Text = firstH1.paragraph.elements[0].textRun.content.trim();
          return h1Text;
        } else {
          console.log("No H1 found in the document");
        }
      } else {
        console.log("No content found in the response");
      }
    } catch (error) {
      console.error("Error:", error.message);
      console.error("Error details:", error.response ? error.response.data : "No additional details available");
    }
  },
});

It looks like you have two separate components: one for extracting the Google Doc ID from the URL, and another for parsing the ID and fetching the document content. To make this work, you can create a single component that combines both functionalities. Here’s a modified version of your code: ```
import { axios } from “@pipedream/platform”; export default defineComponent({ props: { google: { type: “app”, app: “google”, }, docUrl: { type: “string”, label: “Google Doc URL”, }, }, async run({ steps, $ }) { // Extract the document ID from the URL const regex = /document/d/([a-zA-Z0-9-_]+)/; const match = this.docUrl.match(regex); const docId = match ? match[1] : null; if (!docId) { console.error(“Invalid Google Doc URL”); return; } // Fetch the document content using the extracted document ID try { const response = await axios($, { url: https://docs.googleapis.com/v1/documents/${docId}, headers: { Authorization: Bearer ${this.google.$auth.oauth_access_token}, }, }); if (response.body && response.body.content) { const firstH1 = response.body.content.find( (element) => element.paragraph && element.paragraph.paragraphStyle.namedStyleType === “HEADING_1” ); if (firstH1) { const h1Text = firstH1.paragraph.elements[0].textRun.content.trim(); return h1Text; } else { console.log(“No H1 found in the document”); } } else { console.log(“No content found in the response”); } } catch (error) { console.error(“Error:”, error.message); console.error( “Error details:”, error.response ? error.response.data : “No additional details available” ); } }, });