dmferrari
dmferrari

Reputation: 161

Gastby - Add a GraphQL query with parameters in gastby-node.js

Inside gatsby-node.jsI have two queries that gets its data from Contentful. I want to add a new query that loads the data for a particular content based on its slug (a field set in the content model in Contentful).

This is what I have:

  return graphql(
    `
      {
        allContentfulBlogPost {
          edges {
            node {
              id
              slug
            }
          }
        }
        allContentfulCaseStudy(filter: { slug: { ne: "dummy-content" } }) {
          edges {
            node {
              id
              slug
            }
          }
        }
        contentfulCaseStudy(slug: { eq: $slug }) { // <=== Here is the problem
          title
          overview
        }
      }
    `
  )
    .then(result => {
      if (result.errors) {
        console.log("Error retrieving contentful data", result.errors)
      }
    })
    .catch(error => {
      console.log("Error retrieving contentful data", error)
    })
}

So, I want to query that particular case study passing the slug in contentfulCaseStudy(slug: { eq: $slug }) but it doesn't work. It throws this error when I start npm run develop:

 ERROR #85901  GRAPHQL

There was an error in your GraphQL query:

Variable "$slug" is not defined.

File: gatsby-node.js:13:10

Error retrieving contentful data [
  GraphQLError: Variable "$slug" is not defined.
      at Object.leave (C:\Edited\edited\edited\edited\node_modules\graphql\validation\rules\NoUndefinedVariables.js:38:33)
      at Object.leave (C:\Edited\edited\edited\edited\node_modules\graphql\language\visitor.js:345:29)
      at Object.leave (C:\Edited\edited\edited\edited\node_modules\graphql\language\visitor.js:395:21)
      at visit (C:\Edited\edited\edited\edited\node_modules\graphql\language\visitor.js:242:26)
      at validate (C:\Edited\edited\edited\edited\node_modules\graphql\validation\validate.js:73:24)
      at GraphQLRunner.validate (C:\Edited\edited\edited\edited\node_modules\gatsby\dist\query\graphql-runner.js:79:44)
      at GraphQLRunner.query (C:\Edited\edited\edited\edited\node_modules\gatsby\dist\query\graphql-runner.js:144:25)
      at C:\Edited\edited\edited\edited\node_modules\gatsby\dist\bootstrap\create-graphql-runner.js:40:19
      at Object.exports.createPages (C:\Edited\edited\edited\edited\gatsby-node.js:13:10)
      at runAPI (C:\Edited\edited\edited\edited\node_modules\gatsby\dist\utils\api-runner-node.js:259:37)
      at Promise.catch.decorateEvent.pluginName (C:\Edited\edited\edited\edited\node_modules\gatsby\dist\utils\api-runner-node.js:378:15)
      at Promise._execute (C:\Edited\edited\edited\edited\node_modules\bluebird\js\release\debuggability.js:384:9)
      at Promise._resolveFromExecutor (C:\Edited\edited\edited\edited\node_modules\bluebird\js\release\promise.js:518:18)
      at new Promise (C:\Edited\edited\edited\edited\node_modules\bluebird\js\release\promise.js:103:10)
      at C:\Edited\edited\edited\edited\node_modules\gatsby\dist\utils\api-runner-node.js:377:12
      at tryCatcher (C:\Edited\edited\edited\edited\node_modules\bluebird\js\release\util.js:16:23) {
    locations: [ [Object], [Object] ]
  }

Is it possible to request a particular case study passing the slug as parameter? If so, how it's done?

Upvotes: 2

Views: 870

Answers (1)

Ferran Buireu
Ferran Buireu

Reputation: 29316

The short answer is that you can't directly. You can filter with a hardcoded parameter, not with a dynamic pre-queried value.

However, what you are trying to do with $slug is to pass a variable via context API.

The flow that are you trying to achieve is:

  • Fetch and create pages from Contentful data for allContentfulCaseStudy
  • Use the slug of allContentfulCaseStudy in contentfulCaseStudy to filter your query for each contentfulCaseStudy.

So, you need to move your contentfulCaseStudy into your template.js modifying your gatsby-node.js like this:

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions

  const result = await graphql(
    `
      {
        allContentfulCaseStudy(filter: { slug: { ne: "dummy-content" } }) {
          edges {
            node {
              id
              slug
            }
          }
        }
      }
    `
  )

  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`)
    return
  }

  const caseStudyTemplate= path.resolve(`src/templates/case-study.js`)

  result.data.allContentfulCaseStudy.edges.forEach(({ node }) => {
    createPage({
      path,
      component: caseStudyTemplate,
      context: {
        slug: node.slug,
      },
    })
  })
}

Now, in your case-study.js you have available the slug variable since you are passing it via context in your page query. So:

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"

export default function CaseStudy({ data }) {
  const caseStudy= data.contentfulCaseStudy
  return (
    <Layout>
      <div>
        <h1>{caseStudy.title}</h1>
      </div>
    </Layout>
  )
}

export const query = graphql`
  query($slug: String!) {
        contentfulCaseStudy(slug: { eq: $slug }) {
          title
          overview
        }
  }
`

Check your localhost:8000/___graphql playground to see if the nested title and overview are under contentfulCaseStudy or if you need to modify the query structure.

Further Reading:

Upvotes: 1

Related Questions