I'm trying to build the post pages imported from WordPress, I run "gatsby develop" and I head to the URL.
The front page flashes up and then I get this error:
Unhandled Rejection (Error): Expected undefined to be a GraphQL schema.
invariant
C:/Users/Phil/Repositories/Zym/node_modules/graphql/jsutils/invariant.mjs:12
assertSchema
C:/Users/Phil/Repositories/Zym/node_modules/graphql/type/schema.mjs:25
validateSchema
C:/Users/Phil/Repositories/Zym/node_modules/graphql/type/validate.mjs:31
graphqlImpl
C:/Users/Phil/Repositories/Zym/node_modules/graphql/graphql.mjs:44
(anonymous function)
C:/Users/Phil/Repositories/Zym/node_modules/graphql/graphql.mjs:20
graphql
C:/Users/Phil/Repositories/Zym/node_modules/graphql/graphql.mjs:18
The query which is highlighted in my 'PostTemplate.js':
export const query = graphql`
query($id: String!) {
wordpressPost(id: { eq: $id }) {
date
title
slug
content
categories {
name
}
}
}
`;
I run the same query through the GraphiQL interface and it sends me data?
Really unsure as to what I'm doing wrong here, see code bellow from gatsby-node.js
exports.createPages = ({ actions, graphql }) => {
const { createPage } = actions
return graphql(`
{
allWordpressPost {
edges {
node {
id
slug
status
}
}
}
}
`)
.then(result => {
if (result.errors) {
result.errors.forEach(e => console.error(e.toString()))
return Promise.reject(result.errors)
}
const postTemplate = path.resolve(`./src/templates/PostTemplate.js`)
const posts = result.data.allWordpressPost.edges
_.each(posts, ({ node: post }) => {
createPage({
path: `/${post.slug}/`,
component: postTemplate,
context: {
id: post.id,
slug: post.slug
},
})
})
})
})
I've tried updating gatsby-cli -g, and uninstalled node_modules.
I don't think your query is properly formatted in your gatsby-node.js file. It should be as follows:
return graphql(`
query {
allWordpressPost {
edges {
node {
id
slug
status
}
}
}
}
`);
Give that a try and let me know if that works for you.
I've encountered the same error and was able to resolve it by making sure I'm importing graphql directly from gatsby:
What caused the error:
// template file
import { graphql } from 'graphql'
How to fix it:
// template file
import { graphql } from 'gatsby'
Related
I am making an eCommerce platform using Next.js. In the product page, where I use dynamic routes, I used getStaticProps to fetch my product and getStaticPaths to generate the paths to the products that should be statically generated. This works perfectly in development mode but the project does not build. The product prop which is passed from getStaticProps to the page component is undefined in build time.
This is the error I get when trying to build:
Error occurred prerendering page "/product/[id]". Read more:
https://err.sh/next.js/prerender-error TypeError: Cannot destructure
property 'name' of 'product' as it is undefined.
function ProductPage({ product}) {
// product is defined in development but undefined when trying to build
const {
name,
price,
} = product;
// The rest of the component
}
export const getStaticPaths = async () => {
connectDb();
const products = await Product.find();
const paths = products.map(product => ({
params: { id: product._id.toString() },
}));
return {
paths,
fallback: true,
};
};
export const getStaticProps = async ({ params }) => {
connectDb();
const { id } = params;
try {
// getting the product
const product = await Product.findOne({ _id: id });
return {
props: {
product: JSON.parse(JSON.stringify(product)),
},
};
} catch (err) {
console.log(err);
return {
props: {
product: {},
},
};
}
};
export default ProductPage;
why is the product prop defined in development mode but undefined in build time, and how can I fix this?
I recently encountered the exact same issue. I'm not sure what you have put in your //the rest of the component section but I noticed in the getStaticPaths function you specify fallback: true. Make sure you handle this in the page component by adding a skeleton or a loading indicator for pages that didn't yet exist at build time. That did the trick for me.
Looking over the code it seems like the product is undefined likely because the code in the try block failed to return data (or you didn't find a matching document in the MongoDB database?). Can you verify that no error occurs?
This can happen if you're passing the id param as "string" while in your MongoDB database the _id field is of type "ObjectID". You can remedy that by converting the "id" string to an ObjectID using the MongoDB package.
I'm creating dynamic pages in Gatsby, pulling data from Fauna. I've got a query in gastby-node that is throwing an error "Must provide Source", but the query works in GraphiQL. I've include gatsby-node.js below.
exports.createPages = async function({actions, graphql}){
const {data} = await graphql`
query {
fauna {
allCompanies {
data {
slug
}
}
}
}
`
data.fauna.allCompanies.data.forEach(edge => {
const slug = edge.slug
actions.createPages({
path: slug,
component: require.resolve("./src/components/products.js"),
context:{
slug
},
})
})
}
Today I encountered the same error and after some time figured it out. A stupid mistake tbh.
graphql is a function that needs to be called with the query as the parameter ( graphql(`...`) ). I was mistaking it for graphql-tag which I used in apollo as
gql`...`
This should work
exports.createPages = async function ({ actions, graphql }) {
/*
you have to pass the template literal query
in the function graphql(`...`)
*/
const { data } = await graphql(`
query {
fauna {
allCompanies {
data {
slug
}
}
}
}
`)
data.fauna.allCompanies.data.forEach(edge => {
const slug = edge.slug
actions.createPages({
path: slug,
component: require.resolve("./src/components/products.js"),
context: {
slug,
},
})
})
}
Hope this helps !
Trying to refactor my gatsby-node file, by outsourcing a bit of code. Right now trying to do this in my gatsby-node:
const createBlogPostPages = require("./gatsby-utils/createBlogPostPages");
exports.createPages = async ({ actions, graphql, reporter }) => {
//...some code
await createBlogPostPages({ actions, graphql, reporter });
//...some code
}
and my createBlogPostPages, which is in a different file, looks like so:
const path = require("path");
module.exports = async function({ actions, graphql, reporter }) {
const { createPage } = actions;
const blogArticles = await graphql(`
{
allMdx(filter: { fileAbsolutePath: { regex: "/content/blog/.*/" } }) {
edges {
node {
id
fileAbsolutePath
fields {
slug
}
frontmatter {
title
tags
date
tagline
}
}
}
}
}
`);
blogArticles.data.allMdx.edges.forEach(({ node }) => {
let imageFileName = ... //some stuff
createPage({
path: `${node.fields.slug}`,
component: path.resolve(`./src/templates/blog-post.js`),
context: {
slug: `${node.fields.slug}`,
id: node.id,
imageFileName: imageFileName
}
});
});
};
All of this works when its directly in gatsby-node.
However, having moved stuff, I now get:
"gatsby-node.js" threw an error while running the createPages
lifecycle:
blogArticles is not defined
ReferenceError: blogArticles is not defined
gatsby-node.js:177 Object.exports.createPages
/Users/kohlisch/blogproject/gatsby-node.js:177:19
next_tick.js:68 process._tickCallback
internal/process/next_tick.js:68:7
So it looks like it's not waiting for the graphql query to resolve? Or what might this be? I just basically want to move a few things out of my gatsby-node file, into separate functions, so that its not so cluttered. Is this not possible?
There are two rules you need to follow when importing in gatsby-node.js:
1. Use node.js require syntax.
./src/components/util/gatsby-node-functions
const importedFunction = () => {
return Date.now();
};
module.exports.importedFunction = importedFunction;
gatsby-node.js
const { importedFunction } = require(`./src/components/util/gatsby-node-functions`);
// ...
// Use your imported functions
console.log(importedFunction());
Reference: Gatsby repo issue, also incluces hack how to use ES6 import statement if you want to add complexity just for using an import statement.
2. Do not pass gatsby-node.js specific attributes to your imported functions
If you attempt to outsource for example, your createPages function, actions will be undefined:
const importedFunction = (actions, node) => {
const {createPage} = actions; // actions is undefined
createPage({
path: `${node.fields.slug}`,
component: path.resolve(`./src/templates/blog-post.js`),
context: {
slug: `${node.fields.slug}`,
id: node.id,
}
});
};
module.exports.importedFunction = importedFunction;
Feel free to speculate why you cannot pass the attributes. The Gatsby documentation mentions "Redux" for handling state. Maybe Redux does not supply state outside your gatsby-node.js. Correct me if I'm wrong
I'm working on this library https://github.com/ilyaskarim/wertik-js called Wertik JS to make GraphQL + Rest API more easily, In resolvers, when I console log info, it shows undefined. For each module, I have created dynamic resolvers to make things more easy for developers who will use this library.
let object = {
create: async (_:any, args:any, context:any,info: any) => {
console.log(info); // This will be undefined
let v = await validate(validations.create,args.input);
let {success} = v;
if (!success) {
throw new ApolloError("Validation error",statusCodes.BAD_REQUEST.number,{list: v.errors})
}
try {
let createModel = await model.create(args.input);
pubsub.publish(`${camelCase(moduleName)}Created`, { [`${camelCase(moduleName)}Created`]: createModel });
return createModel;
} catch (e) {
return internalServerError(e);
}
},
}
Line: https://github.com/ilyaskarim/wertik-js/blob/ec813f49a14ddd6a04680b261ae4ef2aadc2b1a5/src/framework/dynamic/resolvers.ts#L102
The info is described in Apollo Server Documentation https://www.apollographql.com/docs/apollo-server/essentials/data/#resolver-type-signature, Which says: This argument contains information about the execution state of the query, including the field name, the path to the field from the root, and more. For me, unfortunately, it is getting undefined.
To reproduce the issue:
Download https://github.com/ilyaskarim/wertik-js/tree/development
Yarn install
Go to examples/demo
Run node index.js
Now go to http://localhost:1209/
Enter this mutation for example:
mutation {
createRole(input: {name: "Asd"}) {
name
}
}
This line executes on this mutation https://github.com/ilyaskarim/wertik-js/blob/ec813f49a14ddd6a04680b261ae4ef2aadc2b1a5/src/framework/dynamic/resolvers.ts#L102
And returns undefined on the console.
This is how I setup the application:
const { ApolloServer } = require('apollo-server');
import mutations from "./loadAllMutations";
import queries from "./loadAllQueries";
import resolvers from "./loadAllResolvers";
import subscriptions from "./loadAllSubscriptions";
import schemas from "./loadAllSchemas";
import generalSchema from "./../helpers/generalSchema";
export default function (rootDirectory: string,app: any,configuration: object) {
let allMutations = mutations(rootDirectory);
let allQueries= queries(rootDirectory);
let allSchemas = schemas(rootDirectory);
let allResolvers = resolvers(rootDirectory);
let allSubscriptions = subscriptions(rootDirectory);
let {validateAccessToken} = require(`${rootDirectory}/framework/predefinedModules/user/auth`).default;
let mainSchema = `
${generalSchema}
${allSchemas}
type Subscription {
${allSubscriptions}
}
type Mutation {
${allMutations}
}
type Query {
${allQueries}
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
`;
const server = new ApolloServer({
typeDefs: mainSchema,
resolvers: allResolvers,
context: async (a: any) => {
await validateAccessToken(a.req);
}
});
server.listen(1209).then(({ url, subscriptionsUrl }) => {
console.log(`Server ready at ${url}`);
console.log(`Subscriptions ready at ${subscriptionsUrl}`);
});
}
What could be a possible reason?
You're truncating the parameters received by the resolvers inside this module. If you need to assign a function to some object property, it's much better to just do it like this:
mutations: {
[`create${moduleName}`]: mutations[`create${moduleName}`],
},
This is not only more succinct, but it also means you don't risk accidentally leaving off a parameter, which is what happened here.
I'm trying to query a graphql API via a proxy of another graphql API and am receiving an error. I'm using graphql yoga for my server and connecting to another graphql API from a CMS. Here is my code:
server.js
const { GraphQLServer } = require('graphql-yoga');
const Prismic = require('./prismic.config.js');
const gql = require('graphql-tag');
const typeDefs = `
type Query {
page(lang: String, uid: String): Page
}
type Page {
page_title: [TextField]
}
type TextField {
text: String
}
`
const resolvers = {
Query: {
page: (parent, args, context, info) => {
const query = gql`${context.request.body.query}`;
const result = context.Prismic.query({
query,
variables: { ...args }
})
.then(resp => {
return resp.data.page;
})
.catch(err => console.log(err));
return result;
}
}
}
const server = new GraphQLServer({
typeDefs,
resolvers,
context: req => ({ ...req, Prismic })
})
server.start(() => console.log('Server is running on localhost:4000'))
Here is my query below from graphql playground that comes with Graphql Yoga:
query {
page(lang: "en-gb", uid: "homepage") {
page_title {
text
}
}
}
The error i'm receiving is:
'Query does not pass validation. Violations:\n\nField \'page_title\'
of type \'Json\' must not have a sub selection. (line 3, column 5):\n
page_title {\n ^' } },
The strange thing is I can get a valid response if I hardcode the query without the nested text field as the error suggests on the server like so:
// const query = gql`${context.request.body.query}`;
const query = gql`
query($uid: String!) {
page(lang: "en-gb", uid: $uid) {
page_title
}
}
`;
Attempting to modify my query in graphql playground to not include the nested text field like so:
query {
page(lang: "en-gb", uid: "homepage") {
page_title
}
}
Gives my the following error and does not allow me to make the request at all:
field "page_title" of type "[TextField]" must have a selection of
subfields. Did you mean "page_title { ... }"?
The error suggests that I need to add the nested subfield of text which is intended but when I use this query instead of the hardcoded one on the server it gives me the error mentioned before.
Not sure if i've gone wrong somewhere in my setup?
Thanks
In your GraphQL schema
page_title: [TextField] is not one of the Scalar Types
As a result, during making a query you need to define what exactly fields you need to fetch?
And your fields in the query should be expanded to the level of having only scalar types, so GraphQL will know how to resolve your query.
So this is the only query that should be from the first level (from graphql playground that comes with Graphql Yoga) :
query {
page(lang: "en-gb", uid: "homepage") {
page_title {
text
}
}
}
But the error from the server throws from your approach to make graphql query inside graphql resolver:
const result = context.Prismic.query({
query,
variables: { ...args }
})
So I'm 100% sure that the page_title in Prismic has the custom scalar - JSON. As a result, you can't use the same query for this request.