How to work around GraphQL error, field "x" must not have a selection since type "String" has no subfields - graphql

I am using Gatsby and GraphQL, and I am new to GraphQL.
I have the following schema definition:
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type MarkdownRemark implements Node {
frontmatter: Frontmatter
}
type Frontmatter {
title: String!
products: [Product]
}
type Product #dontInfer {
name: String!
price(price: Int = 1): Float
description: String
images: [ProductImage]
}
type ProductImage {
url: String
}
`;
createTypes(typeDefs);
};
Then on my page I use the following query:
query {
markdownRemark(fileRelativePath: { eq: "/content/pages/products.md" }) {
...TinaRemark
frontmatter {
title
products {
name
price
description
images {
url {
childImageSharp {
fluid(maxWidth: 1920) {
...GatsbyImageSharpFluid_withWebp
}
}
}
}
}
}
html
}
}
I then receive the following error:
Field "url" must not have a selection since type "String" has no subfields.
Does anyone have any suggestions on how to work around this error?
Also, what is childImageSharp? I'm wondering what the terminology is to define it. Is it a GraphQL "selector" or "function"?

It should be
query {
markdownRemark(fileRelativePath: { eq: "/content/pages/products.md" }) {
...TinaRemark
frontmatter {
title
products {
name
price
description
images {
url
}
}
}
html
}
}
Because you definition is
type ProductImage {
url: String
}
The url apparently has no sub fields.

For what it's worth (I don't know if this is related to your specific issue.) If your markdown path for the image file is invalid, GraphQL will return this error, interpreting the path as a string. I had this problem and it went away when I realized I had misspelled the path in the markdown.
productImage {
childImageSharp {
gatsbyImageData(width: 200)
}
}

I had a similar problem with returning a boolean. For me, instead of something like this
mutation {
someFunc(
memo: "test memo"
) {
success
}
}
I needed this
mutation {
someFunc(
memo: "test memo"
)
}

Related

How to pass variables to strapi graphql api?

I have the following graphql code in my strapi and nextjs project. The code is working in the graphql end point playground but some how it keeps getting error in my local environment showing message: 'Syntax Error: Expected Name, found <EOF>.', when I try to fetch data from nextjs. I have ready this strapi documentation but cant seems to find anything relevant with my current issues. Any can please tell me what error I am making here?
export async function getPostAndMorePosts(slug, preview) {
const data = await fetchAPI(
`
fragment FileParts on UploadFileEntityResponse {
data {
id
attributes {
alternativeText
width
height
mime
url
formats
}
}
}
query Posts($slug: String!) {
posts(filters: {slug: {eq: $slug}}) {
data{
attributes{
title
content
excerpt
slug
category{
data{
attributes{
name
}
}
}
coverImage{
...FileParts
}
}
}
}
morePost: posts(filters: {slug: {ne: $slug}},pagination: { start: 0, limit: 4 }) {
data{
attributes{
title
content
excerpt
slug
category{
data{
attributes{
name
}
}
}
coverImage{
...FileParts
}
publishedAt
}
}
}
}`,
{variables:{
slug:slug
}
}
)
return data
}
Your code needs a closing bracket which is misaligned at the moment! Look at the code below
export async function getPostAndMorePosts(slug, preview) {
const data = await fetchAPI(
`
fragment FileParts on UploadFileEntityResponse {
data {
id
attributes {
alternativeText
width
height
mime
url
formats
}
}
}
} -> closed here
query Posts($slug: String!) {
posts(filters: {slug: {eq: $slug}}) {
data{
attributes{
title
content
excerpt
slug
category{
data{
attributes{
name
}
}
}
coverImage{
...FileParts
}
}
}
}
morePost: posts(filters: {slug: {ne: $slug}},pagination: { start: 0, limit: 4 }) {
data{
attributes{
title
content
excerpt
slug
category{
data{
attributes{
name
}
}
}
coverImage{
...FileParts
}
publishedAt
}
}
}
`, -> removed from here
{variables:{
slug:slug
}
}
)
return data
}
So it's just an issue of {} alligment.

Nextjs - Contentful - Tags - Dynamic pages

I would like to create dynamic pages when I click a tag in an article or elsewhere on my website.
I'm using Next.js, SSG, and fetching the articles containing the tags from Contentful with the following GraphQL queries:
export async function getArticles() {
const articlesQuery = gql`
{
articleCollection(order: date_DESC) {
items {
title
slug
excerpt
date
contentfulMetadata {
tags {
name
id
}
}
featuredImage {
title
url
width
height
}
author {
name
photo {
fileName
url
width
height
}
title
twitterProfile
linkedInProfile
slug
}
}
}
}
`;
return graphQLClient.request(articlesQuery);
}
export async function getArticle(slug) {
const articleQuery = gql`
query getArticle($slug: String!) {
articleCollection(limit: 1, where: { slug: $slug }) {
items {
title
slug
excerpt
date
contentfulMetadata {
tags {
name
id
}
}
featuredImage {
title
url
width
height
}
author {
name
photo {
fileName
url
width
height
}
title
twitterProfile
linkedInProfile
slug
}
content {
json
links {
entries {
block {
sys {
id
}
__typename
... on VideoEmbed {
title
embedUrl
}
... on CodeBlock {
description
language
code
}
}
}
assets {
block {
sys {
id
}
url
title
width
height
}
}
}
}
}
}
}
`;
return graphQLClient.request(articleQuery, {
slug,
});
}
The contentfulMetadata is where the tags come from:
contentfulMetadata {
tags {
name
id
}
}
This is my [id].jsx file:
import { getArticles, getArticle } from "#utils/contentful";
export async function getStaticPaths() {
const data = await getArticles();
return {
paths: data.articleCollection.items.map((article) => ({
params: { id: article.contentfulMetadata.tags[0].id },
})),
fallback: false,
};
}
export async function getStaticProps(context) {
const data = await getArticle(context.params.id);
return {
props: { article: data.articleCollection.items[0] },
};
}
export default function TagPage({ article }) {
return (
<div>
<h1>{article.contentfulMetadata.tags.id}</h1>
</div>
);
}
I get the following error:
Error: Error serializing `.article` returned from `getStaticProps` in "/tags/[id]". Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.
When console.log(data.articleCollection.items.contentfulMetadata.tags.id); or console.log(data.articleCollection.items.contentfulMetadata.tags[0].id); within getStaticPaths function it provides the following error:
TypeError: Cannot read property 'tags' of undefined
Can anyone show how to create a dynamic page ([id].jsx) file, which shows the tag id as the header <h1> as well as all articles containing the same tag?
Contentful DevRel here 👋🏼.
article.contentfulMetadata.tags is an array, as an entry can have more than one tag. So you'll need to access the tag you want via article.contentfulMetadata.tags[0].id or article.contentfulMetadata.tags[desired_index].id and so on.
Here's an example GraphQL query:
query {
blogPostCollection {
items {
contentfulMetadata {
tags {
id
name
}
}
}
}
}
And here's the response with tags as an array:
"data": {
"blogPostCollection": {
"items": [
{
"contentfulMetadata": {
"tags": [
{
"id": "salmastag",
"name": "Salma s tag"
}
]
}
},
{
"contentfulMetadata": {
"tags": []
}
}
]
}
}
}
Notice how if a blog post doesn't have any PUBLIC tags assigned (the second entry in the response), an empty array is returned — you might want to do some safety checking in your code for this.

GraphQL error: Variable $customerAccessToken of type String! was provided invalid value

I'm attempting to recover a customer using the customerAccessToken that is given when the user logs in to Shopify.
Using Apollo, here's my code:
this.apollo.mutate({
mutation: getCustomerFromToken,
variables: {
input: {
customerAccessToken: '217b9a6952c28eb4db376487a6301294' // Also tried btoa('217b9a6952c28eb4db376487a6301294')
}
},
})
Here's my GraphQL query:
query getCustomerFromToken($customerAccessToken: String!) {
customer(customerAccessToken: $customerAccessToken) {
id
addresses(first: 5) {
edges {
node {
address1
address2
company
city
province
zip
country
phone
}
}
}
orders(first: 200) {
edges {
cursor
node {
id
totalPriceV2 {
amount
currencyCode
}
processedAt
orderNumber
}
}
}
}
}
Here's the login GraphQL code I'm using to retrieve the accessToken from Shopify:
mutation customerAccessTokenCreate($input: CustomerAccessTokenCreateInput!) {
customerAccessTokenCreate(input: $input) {
customerAccessToken {
accessToken
expiresAt
}
customerUserErrors {
code
field
message
}
}
}
My problem was two fold.
I was using a mutation on a query end point
Queries don't use input in the payload
const payload = {
customerAccessToken: "..."
}
// NOT
const payload = {
input: {
customerAccessToken: "..."
}
}

GQL scheme to accept multiple data structure for same key

I'm currently using GQL Modules in my app.
In the below data structure, content will have either object or array
var A = {
content: {
text: "Hello"
}
}
var B = {
content: {
banner: [{
text: "Hello"
}]
}
}
How do I make content to accept dynamic schema ?
Below is what I tired, but not working. Please help
type body {
content: TextContent | [Banner]
}
type Banner {
text: TextContent
}
type TextContent {
text: String
}
GraphQL requires that a field always resolves to either a single value or a list -- it cannot resolve to either. A field can however, return different types altogether at runtime using an abstract type (either a union or an interface). So you can restructure your schema like this:
type Body {
content: Content
}
union Content = TextContent | BannerContent
type TextContent {
text: String
}
type BannerContent {
banners: [Banner]
}
You would then query content using fragments:
query {
someField {
body {
content: {
...on TextContent {
text
}
...on BannerContent {
banners
}
}
}
}
}

GraphQL filters in GatsbyJS

I'm having trouble understanding how to write filters for GraphQL queries in GatsbyJS.
This works:
filter: { contentType: { in: ["post", "page"] }
I basically need the reverse of that, like:
filter: { "post" in: { contentTypes } } // where contentTypes is array
That doesn't work because "NAME is expected" (where "post" is in my example).
After going through GatsbyJS docs I found this:
elemMatch: short for element match, this indicates that the field you are filtering will return an array of elements, on which you can apply a filter using the previous operators
filter:{
packageJson:{
dependencies:{
elemMatch:{
name:{
eq:"chokidar"
}
}
}
}
}
Great! That's what I need! So I try that, and I get:
error GraphQL Error Field "elemMatch" is not defined by type markdownRemarkConnectionFrontmatterTagsQueryList_2.
Keywords defined in markdownRemarkConnectionFrontmatterTagsQueryList_2 are:
eq: string | null;
ne: string | null;
regex: string | null;
glob: string | null;
in: Array | null;
Why am I limited to these keywords when more keywords such as elemMatch are mentioned in docs? Why am I not allowed to use the filter structure "element in: { array }"?
How can I create this filter?
Filter by value in an array
Let's say you have a markdown blog with categories as an array of string, you can filter posts with "historical" in categories like this:
{
allMarkdownRemark(filter:{
frontmatter:{
categories: {
in: ["historical"]
}
}
}) {
edges {
node {
id
frontmatter {
categories
}
}
}
}
}
You can try this query out in any of the graphiq blocks in Gatsby.js docs.
ElemMatch
I think elemMatch is only 'turned on' for fields with array of objects; something like comments: [{ id: "1", content: "" }, { id: "2", content: ""}]. This way, you can apply further filters on the fields of each comment:
comments: { elemMatch: { id: { eq: "1" } } }
Here's an example you can try out in the graphiq blocks in gatsby docs:
// only show plugins which have "#babel/runtime" as a dependency
{
allSitePlugin (filter:{
packageJson:{
dependencies: {
elemMatch: {
name: {
eq: "#babel/runtime"
}
}
}
}
}) {
edges {
node {
name
version
packageJson {
dependencies {
name
}
}
}
}
}
}

Resources