gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.28k stars 10.31k forks source link

Source Plugins: How to query nodes inside an api's object id #12356

Closed PHironaka closed 5 years ago

PHironaka commented 5 years ago

Summary

I'm building a Gatsby source plugin for the first time and running into issues fetching data. I was using this tutorial for guidance, but the way my API is structured is different.

I'm using the storelocatorwidget's API.

I would like to be able to query all the data inside each store's id (which is an object).

I'm able to find each store id (in the example above that would be '13466445'), but I would also like to query all the nodes inside that object id.

I've included both the gatsby-config.js file as well as the plugin's gatsby-node.js file for reference. Any tips would be appreciated.

Relevant information

Here is a sampling of store data that gets returned, for context on how their data is structured:

{
  "status": "OK",
  "locations": {
    "13466445": {
      "name": "Village Green Society",
      "display_order": "999999",
      "filters": null,
      "createstamp": "1536191260",
      "editstamp": "1546982631",
      "geocodestatus": "Manual",
      "geocodetimestamp": "0",
      "google_placeid": "",
      "locationid": "13466445",
      "description": "",
      "address": "2043 16th St, Boulder, CO, 80302, US",
      "image": "",
      "website": "https://villagegreenboulder.com/",
      "website_text": "",
      "facebook": "",
      "instagram": "https://www.instagram.com/villagegreenboulder/",
      "twitter": "",
      "phone": "(720) 389-5726",
      "phone2": "",
      "fax": "",
      "email": "",
      "hours_Monday": "",
      "hours_Tuesday": "",
      "hours_Wednesday": "",
      "hours_Thursday": "",
      "hours_Friday": "",
      "hours_Saturday": "",
      "hours_Sunday": "",
      "store_list_footer": "",
      "print_directions_button": null,
      "map_lat": "40.019788",
      "map_lng": "-105.275335",
      "priority_type": "",
      "priority_setting": "Random",
      "z_index": "",
      "visibility": "",
      "markerid": "default"
    },
},
}

Environment (if relevant)

File contents (if changed)

gatsby-config.js:

module.exports = {
  siteMetadata: {
    title: `Gatsby Default Starter`,
    description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
    author: `@gatsbyjs`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },

    {
      resolve: "gatsby-source-store-locator-widget",
      options: {
        api_key: "<API-KEY>",
      },
    },

    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#663399`,
        theme_color: `#663399`,
        display: `minimal-ui`,
        icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
      },
    },
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.dev/offline
    // 'gatsby-plugin-offline',
  ],
}

package.json: N/A gatsby-node.js:

const fetch = require("node-fetch")
const queryString = require("query-string")

exports.sourceNodes = (
  { actions, createNodeId, createContentDigest },
  configOptions
) => {
  const { createNode } = actions

  // Gatsby adds a configOption that's not needed for this plugin, delete it
  delete configOptions.plugins
//   // Helper function that processes a photo to match Gatsby's node structure
  const processShop = shop => {
    const nodeId = createNodeId(`store-locator-widget-photo-${shop}`)
    const nodeContent = JSON.stringify(shop)
    const nodeData = Object.assign({}, shop, {
      id: nodeId,
      parent: nodeId,
      children: {},
      internal: {
        type: `StoreLocatorWidgetId`,
        content: nodeContent,
        contentDigest: createContentDigest(shop),
      },
    })

    return nodeData
  }

  // Convert the options object into a query string
  const apiOptions = queryString.stringify(configOptions)

  // Join apiOptions with the Pixabay API URL
  const apiUrl = `https://www.storelocatorwidgets.com/admin/api/v1/locations?${apiOptions}`

  // Gatsby expects sourceNodes to return a promise
  return (
    // Fetch a response from the apiUrl
    fetch(apiUrl)
      // Parse the response as JSON
      .then(response => response.json())
      // Process the response data into a node
      .then(data => {
        // For each query result (or 'hit')
        Object.keys(data.locations).forEach(shop => {
            console.log("shop data is:", shop)
            const nodeData = processShop(shop)
            createNode(nodeData)
        })
      })
  )
}

gatsby-browser.js: N/A gatsby-ssr.js: N/A

PHironaka commented 5 years ago

closing this issue. The problem was w/the nodeId in my helper, it was just pulling in the id and not the store object.

change to my gatsby-node.js file below helped solve the issue, thank you @LekoArts for the assist!

const fetch = require("node-fetch")
const queryString = require("query-string")

exports.sourceNodes = (
  { actions, createNodeId, createContentDigest },
  configOptions
) => {
  const { createNode } = actions

  // Gatsby adds a configOption that's not needed for this plugin, delete it
  delete configOptions.plugins
//   // Helper function that processes a photo to match Gatsby's node structure
const processShop = (id, shop) => {
  const nodeId = createNodeId(`store-locator-widget-photo-${id}`)
  const nodeContent = JSON.stringify(shop)
  const nodeData = Object.assign({}, shop, {
    id: nodeId,
    parent: nodeId,
    children: {},
    internal: {
      type: `StoreLocatorWidgetId`,
      content: nodeContent,
      contentDigest: createContentDigest(shop),
    },
  })

  return nodeData
}

  // Convert the options object into a query string
  const apiOptions = queryString.stringify(configOptions)

  // Join apiOptions with the Pixabay API URL
  const apiUrl = `https://www.storelocatorwidgets.com/admin/api/v1/locations?${apiOptions}`

  // Gatsby expects sourceNodes to return a promise
  return (
    // Fetch a response from the apiUrl
    fetch(apiUrl)
      // Parse the response as JSON
      .then(response => response.json())
      // Process the response data into a node
      .then(data => {

        Object.entries(data.locations).forEach(([key, shop]) => {
          console.log(shop)
          const nodeData = processShop(key, shop)
          createNode(nodeData)

        })

      })
  )
}