{"componentChunkName":"component---src-templates-post-js","path":"/google-sheets-gatsby/","result":{"data":{"mdx":{"id":"261fcb5e-5d4c-50cb-afdd-b50056570d5d","body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Using Google Sheets as a Gatsby Backend\",\n  \"date\": \"2021-01-24T00:00:00.000Z\",\n  \"featuredImage\": \"sheets-gatsby-thumb.png\",\n  \"caption\": \"Google Sheets and Gatsby's GraphQL work great together\",\n  \"description\": \"Recently hooked up this Gatsby site to a few of my Google Sheets to display tabular data. The available plugins make this task a snap.\",\n  \"published\": true\n};\n\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\n\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"h2\", null, \"GatsbyJS \\u2764\\uFE0F Google Sheets\"), mdx(\"p\", null, \"One of the reasons I love working with Gatsby specifically, and React in general, is how easy it usually is to find a plugin to solve whatever problem you're trying to solve. I'm a big fan of not reinventing the wheel. Chances are, you're not the first developer in the world who has come up against a certain use case, so it's usually just a matter of building off of someone else's solution. It turns out that it's very easy to set up an ad hoc backend for Gatsby with Google Sheets by using the \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://www.gatsbyjs.com/plugins/gatsby-source-google-spreadsheets/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"gatsby-source-google-spreadsheets\"), \" plugin by \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/butlerx\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"Cian Butler\"), \".\"), mdx(\"h3\", null, \"The Query\"), mdx(\"p\", null, \"Following the \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://www.gatsbyjs.com/plugins/gatsby-source-google-spreadsheets/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"instructions on the plugin's page\"), \", it's simple enough to configure. The only gotcha which I will go into detail below is using a Google Sheets API key in your Gatsby site. Once configured, you should see your specified spreadsheet show up in the GraphQL query explorer, which can be found at \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"http://localhost:8000/___graphql\"), \" if you've run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"gatsby develop\"), \" from the command line. \"), mdx(\"p\", null, \"Once you can confirm that the data is coming into your Gatsby site this way, you can run a query inside one of your components to render the data. Spreedsheet tabs will show up at the root level of your site's query explorer with a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"allGoogle[Tab]Sheet\"), \" naming convention, and spreadsheet columns will be converted to nodes. As an example, this is how the query from my \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/reads\"\n  }), \"reading list\"), \" tab of my spreadsheet data looks, grabbing just the nodes I need:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"// GraphQL query for reads.js\\n\\nconst data = useStaticQuery(graphql`\\n  query {\\n    allGoogleReadsSheet {\\n      nodes {\\n        author\\n        addAuthors\\n        dateRead\\n        title\\n      }\\n    }\\n  }\\n`)\\n\")), mdx(\"h3\", null, \"Mapping the Results\"), mdx(\"p\", null, \"With the query established, using the React hook, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"useState\"), \", to set the starting year for my \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://react-bootstrap.github.io/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"Bootstrap\"), \" tabs, it's just a matter of iterating through the data with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"map()\"), \". In the example below, I've separated the data into tabs by year, so I first iterate through the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"years\"), \" array before iterating through the query data, only returning entries that match the selected year. This is a sample of my completed \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/reads\"\n  }), \"reading list\"), \" JSX:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"// reads.js\\n\\n// import statements, yada yada yada\\n// ...\\n\\nconst ReadsPage = props => {\\n  const [yearSelected, setYearSelected] = useState(2021)\\n  const years = [2021,2020,2019]\\n\\n  const data = useStaticQuery(graphql`\\n    query {\\n      allGoogleReadsSheet {\\n        nodes {\\n          author\\n          addAuthors\\n          dateRead\\n          title\\n        }\\n      }\\n    }\\n  `)\\n  return (\\n  // ...\\n    <h2 className=\\\"mt-4\\\">Books Read</h2>\\n    <p className=\\\"mb-4 h5\\\">Sorted by Year Finished, then Author</p>\\n    <Tabs\\n      id=\\\"books-read\\\"\\n      activeKey={yearSelected}\\n      onSelect={(k) => setYearSelected(k)}\\n    >\\n      {years.map((year, index) => { // iterating through `years` array\\n        return (\\n          <Tab key={year} eventKey={year} title={year}>\\n            <Table responsive=\\\"sm\\\">\\n              <thead>\\n                <tr>\\n                  <th style={{ width: '50%' }}>Title</th>\\n                  <th>Authors</th>\\n                  <th className=\\\"text-right\\\" width=\\\"135\\\">\\n                    Date Finished\\n                  </th>\\n                </tr>\\n              </thead>\\n              <tbody>\\n                {data.allGoogleReadsSheet.nodes.map(({ \\n                  // this is where the GraphQL magic happens\\n                  author,\\n                  addAuthors,\\n                  dateRead,\\n                  title\\n                }, index) => {\\n                  return dateRead \\n                  && dateRead.includes(year)\\n                  && (\\n                    <tr key={index}>\\n                      <td>{title}</td>\\n                      <td>\\n                        {author}\\n                        {addAuthors && (<>,<br/>{addAuthors}</>)}\\n                      </td>\\n                      <td className=\\\"text-right\\\">{dateRead}</td>\\n                    </tr>\\n                  )\\n                })}\\n              </tbody>\\n            </Table>\\n          </Tab>\\n        )\\n      })}\\n    </Tabs>\\n// ...\\n)}\\n\\nexport default ReadsPage\\n\")), mdx(\"h3\", null, \"Environment Variables\"), mdx(\"p\", null, \"As mentioned above, the one gotcha I ran into using the latest version of Google Sheets API and \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://www.gatsbyjs.com/plugins/gatsby-source-google-spreadsheets/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"gatsby-source-google-spreadsheets\"), \" is the need to use an API key. While it's a trivial task to set up a free API key in Google's developer console, I made the rookie move of including said API key in my source code. \\uD83D\\uDE2C This was immediately flagged by Github as a security risk and I quickly got a crash course in Gatsby/Gatsby Cloud environment variables. Fortunately, they really do make it easy (\", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"see documentation\"), \"). \"), mdx(\"p\", null, \"For my local build, I simply had to create a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"src/.env.development\"), \" file with the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"SHEET\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"API_KEY\"), \" variables specified, and made sure to hide it from Git in my \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".gitignore\"), \" file. For the \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://www.gatsbyjs.com/cloud/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"Gatsby Cloud\"), \" interface, it only takes a few clicks to define the same variables for production builds. Take a look at my modified \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"gatsby-config.js\"), \" file with properly hidden env variables: \"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-js\"\n  }), \"// gatsby-config.js\\n\\n// somewhere halfway down the page...\\n{\\n  resolve: 'gatsby-source-google-spreadsheets',\\n  options: {\\n    spreadsheetId: process.env.SHEET,\\n    apiKey: process.env.API_KEY\\n  }\\n},\\n// ...\\n\")), mdx(\"h3\", null, \"Going Forward\"), mdx(\"p\", null, \"Knowing what I now know about GraphQL makes me want to do a full rewrite of \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"http://stringbanddatabase.com/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"String Band Database\"), \", a project I initially wrote in jQuery back in \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://mummers.github.io/stringbands/sbdb-1.0/index.html\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"2013\"), \" using a plugin called \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://chriszarate.github.io/sheetrock/\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"Sheetrock\"), \" that allows you to do SQL-like queries against a public Google spreadsheet. The project has since been moved over to Github Pages and is spearheaded by my fellow banjo player and web developer, \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://tjferry.com\",\n    \"target\": \"_blank\",\n    \"rel\": \"nofollow noopener noreferrer\"\n  }), \"TJ Ferry\"), \", who has done a bang-up job adding new features and curating the content. \"), mdx(\"p\", null, \"The time to modernize our searchable listing of old string band themes is nigh!\"));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"Using Google Sheets as a Gatsby Backend","date":"Sunday, January 24, 2021","description":"Recently hooked up this Gatsby site to a few of my Google Sheets to display tabular data. The available plugins make this task a snap.","caption":"Google Sheets and Gatsby's GraphQL work great together","featuredImage":{"childImageSharp":{"sizes":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsSAAALEgHS3X78AAACi0lEQVQoz02TO2sUURiGp/Qf+CdsBAsLtbASEVNEsDUWRiwiFoLxLqJgUMQYEZXECK5RQROQ3NyYkGgihgSVaPaW3ZnZmdmZndvuJrvZdI/nnFyw+JipnvO+3/t+Wqphkl23yK3byP/lhkGmbpGuWaxUHPKhSzHwsbwQ0xRfI6Skx9i5CCcf4+oVPKOCK8Yzq2hZAcoIYKpRxGh6WBs+TjNEr7sUqiUKAqiXPcySgFkBtgD6do3IWyNy1ygVYjUSLB/Qsgpmkm+WSMYL9LqjJNwJUjUTs+azEpb+A4aU3SrpBZvpD8vMj68oZWWhbFuplhbKpM2iUNb69wba9EG05AGOjJ4lFZnokVAdh8qyH1aZHUnz4vIE/Ten6L02yWDPjx3YjmWp0GyWObl8m93fW9m7cIZdycM8LQwR1daY+/2TnGFRyJV5eWuKx+dHad/3jCstA3Qc6uPLwBKxt2lfKZRTaLq0Zx/SZb1jKJzlXL6b7uIgXhBz/EQrrxIJ0r88ujuGeX13hlN7nnDpWIKeC2O8fzBHNWhgZUI0qe5PXVeBtGW6OJ25zx0zwdGlTh7pH5XCmcV50nkDI+/zvDPJ3KcMb+59417bkIJPvl3aDEiGIusigfZGQMufq2iT+9n19Qja1H56DGG5uopdjdUOvaDC7HCavuuTPL34We1yoOsbzkqk9ihHWZZQXVgei+ZFyiP0u+P02iMsRlnMyCfvuTsph/4qy/O22tv34awKIxA1kmmrHUrLuXWHjADLYJyNUPQwoFSPKFRcjNjD8MtCoeigE2HpIYFToxo2CEurCrJdcAXcvBJHVMfkb91QFUrVi2RWxaVsFXtboW2LKykKwFaRt8ssdycrI4H/ANwI89jSK3wPAAAAAElFTkSuQmCC","aspectRatio":1.834862385321101,"src":"/static/64f8c5c135ddf2cc48343ad80b81c34f/bc8e0/sheets-gatsby-thumb.png","srcSet":"/static/64f8c5c135ddf2cc48343ad80b81c34f/8ac63/sheets-gatsby-thumb.png 200w,\n/static/64f8c5c135ddf2cc48343ad80b81c34f/3891b/sheets-gatsby-thumb.png 400w,\n/static/64f8c5c135ddf2cc48343ad80b81c34f/bc8e0/sheets-gatsby-thumb.png 800w,\n/static/64f8c5c135ddf2cc48343ad80b81c34f/6050d/sheets-gatsby-thumb.png 1200w","srcWebp":"/static/64f8c5c135ddf2cc48343ad80b81c34f/ccdb5/sheets-gatsby-thumb.webp","srcSetWebp":"/static/64f8c5c135ddf2cc48343ad80b81c34f/6b183/sheets-gatsby-thumb.webp 200w,\n/static/64f8c5c135ddf2cc48343ad80b81c34f/fc32b/sheets-gatsby-thumb.webp 400w,\n/static/64f8c5c135ddf2cc48343ad80b81c34f/ccdb5/sheets-gatsby-thumb.webp 800w,\n/static/64f8c5c135ddf2cc48343ad80b81c34f/9000d/sheets-gatsby-thumb.webp 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"thumbnail":null}}},"pageContext":{"id":"261fcb5e-5d4c-50cb-afdd-b50056570d5d"}},"staticQueryHashes":["284470141","3649515864","63159454"]}