A reference field in Contentful limited to a single Entry but which accepts many types results in an incorrect GraphQL type being generated.
e.g. This "Full Slot field" is a reference to a single Entry, and accepts multiple Entry Types:
However, the fullSlot
GraphQL field incorrectly has its type set to ContentfulPlainTextModuleTest
instead of a Union(ContentfulPlainTextModuleTest|ContentfulMediaModule
) or something similar.
This results in an error running queries when multiple types appear for this reference field. e.g
query AllFullSlices {
allContentfulSliceFull {
edges {
node {
fullSlot {
__typename
}
}
}
}
}
{
"errors": [
{
"message": "Expected value of type \"ContentfulPlainTextModuleTest\" but got: [object Object].",
"locations": [
{
"line": 30,
"column": 9
}
],
"path": [
"allContentfulSliceFull",
"edges",
0,
"node",
"fullSlot"
]
}
],
"data": {
"allContentfulSliceFull": {
"edges": [
{
"node": {
"fullSlot": null
}
},
{
"node": {
"fullSlot": {
"__typename": "ContentfulPlainTextModuleTest"
}
}
}
]
}
}
}
You can see the inferred type for fullSlot
is set incorrectly in Graphiql:
Having done a lot of console.log
-ing, it seems like the issue comes from the logic that extracts an "example value" for a given node: https://github.com/gatsbyjs/gatsby/blob/3945d0132d8b3caa32940a2749ab4809bc13d310/packages/gatsby/src/schema/data-tree-utils.js#L52
Maybe a fix is to wrap any Contentful reference fields in an array?
Our current work around is just going to be to convert Contentful references into "many" references so that way the Union types are built correctly and our project can build again.
Gatsby version: 1.9.145
Node.js version: v8.9.4
Operating System: macOS 10.13.2
Gatsby infers a single type for a singular reference field.
Gatsby should infer a Union type for a singular reference field representing all possible types of the linked Entries.
1. Create a Gatsby content type with a "single reference" field
2. Add two entries to that reference field of different types
3. Observe the generated GraphQL schema for that content type
...
This came out of investigation + context in #3495
/cc @Khaledgarbaya
👋 yeah this might be a bug, I need to investigate further I think for now a workaround is to change the field to an array of references and only put 1 item since it is handled correctly.
Yep - that's the work around we're going with for now just to keep moving. I'm going to try and take more of a look into the gatsby-source-contentful
code and see if I can contribute anything here as well. Thanks for looking into it @Khaledgarbaya 🙂
Hi guys, similar case, I thought I’d ask my question here instead of opening a new issue.
How do I query for the content under "fullSlot"? It seems I can only query for __typename.
EDIT: my "fullSlot" has many references. It can accept type of Series and Products. If I have a mix of Series and Products as its references, I can only query for __typename. If however, I have many of the same type, it works.
EDIT2: just learned how GraphQL Union works and solved my own question. If anyone faces the same problem as I did, look up Inline Fragments. Here’s how it looks like:
Thanks.
Hi. Has there been any progress for this?
Thanks @ryanditjia for the pointer in the right direction. I got fragments working also, for anyone who wants to see code for that: https://github.com/ahimsayoga/ahimsayogajp/pull/32/files#diff-b8465397efd9d164185ae5772e69ecf0R42
I've been bitten by this a couple times now and would love to see this resolved. Is there any way a one-field reference can be treated like an array as far as GraphQL queries are concerned? This is especially challenging because…
one
reference field is created in Contentful, it can't be switched to many
- Once a field name is used, it cannot be reused (even if you delete and recreate), forcing a rename of the field
I just tried creating a testField, deleting and recreating with same name and field ID seems to work. Not sure why it doesn’t on your end.
- Renaming fields in Contentful when a new type is added requires changing the field name throughout GraphQL queries and the components that use the field
I share your pain, but I try to relieve it by creating 2 of the same fields—suffixing one with workaround
. For example reference
and referenceWorkaround
where referenceWorkaround
is the band-aid solution (many references, but set to accept only 1 entry in the Validations tab).
In the GraphQL query:
ctaButtons {
text
# delete below line and this comment when bug is fixed
reference: referenceWorkaround {
# uncomment below line when bug is fixed, then delete this comment
# reference {
__typename
... on ContentfulBrand {
slug
}
... on ContentfulProduct {
slug
brand {
slug
}
}
}
}
And then, in the component:
// You don’t have to modify component code when bug is fixed
const oneOrMany = ref => (Array.isArray(ref) ? ref[0] : ref)
const reference = data.ctaButtons.reference ? oneOrMany(data.ctaButtons.reference) : null
return (
<Link href={getPathByReference(reference)}>{text}</Link>
)
This way, when the bug is fixed you only need to modify the query a little bit.
Catch is: it requires the content manager to input both fields, or you automating the migration from referenceWorkaround
to reference
when the bug is fixed.
Renaming fields in Contentful when a new type is added requires changing the field name throughout GraphQL queries and the components that use the field
You actually can rename a field id in Contentful using the Webapp.
You click the lock icon and change the fields id
You might want to use the migration tool to do all these fields transformation
That took me some time (after a lot of deletion + re-creation) to find too. Opportunity for an UX improvement, @Khaledgarbaya!
@ryanditjia I will transfer that to the team
@Khaledgarbaya I had no idea that lock was a button! I assumed it meant that the field couldn't be edited. 🙌
@ryanditjia Thanks for the tip about fooWorkaround
. I didn't realize graphql supported aliases like that; that's very useful!
I just tried creating a testField, deleting and recreating with same name and field ID seems to work. Not sure why it doesn’t on your end.
Contentful won't load for me today so I can't try this again, but I think this specifically is the case after you save the model, but it could be when you have data. Or it might only be that you can't create a new model with the same name? I can't be sure without confirming.
I have similar issue, Workaround for the issue seems to be fine. But I cant't delete the fields since we have around 200 records already updated.
Any update on permanent fix for the issue?
Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!
If anyone is still having this issue, this is what I did to resolve it.
https://github.com/gatsbyjs/gatsby/issues/10090#issuecomment-450766497
Most helpful comment
Hi guys, similar case, I thought I’d ask my question here instead of opening a new issue.
How do I query for the content under "fullSlot"? It seems I can only query for __typename.
EDIT: my "fullSlot" has many references. It can accept type of Series and Products. If I have a mix of Series and Products as its references, I can only query for __typename. If however, I have many of the same type, it works.
EDIT2: just learned how GraphQL Union works and solved my own question. If anyone faces the same problem as I did, look up Inline Fragments. Here’s how it looks like:
Thanks.