I have the following code ...
const createThenReference = async () => {
return await axios.post('http://localhost:1337/firsts', {
name: "Jeremy"
})
.then(async (res)=>{
await axios.post('http://localhost:1337/seconds', {
name: "Jonathan",
first: res.data
})
.then((res)=>{console.log(res)})
.catch((err)=>{console.log(err)})
})
.catch((err)=>{console.log(err)})
}
The fields of each table is as follows ...
First = { name: String, second: Relationship }
Second = { name: String, first: Relationship }
What I am trying to achieve is that after the firsts entry is created, a new one in seconds is created and it references back to the firsts in a 1-to-1 reference.
I've had success referencing items that were already created in a similar way of just passing them into their appropriate field in the payload. However, when it is recently created I have issues. -- I'm unable to find any documentation that even talks about creating references from the front end.
Apparently you can simply pass in the ID of the table entry that has a relationship to that field. -- Which is odd because I remember trying that before and it didn't work.
I changed ...
await axios.post('http://localhost:1337/seconds', {
name: "Jonathan",
first: res.data
})
to
await axios.post('http://localhost:1337/seconds', {
name: "Jonathan",
first: res.data.id
})
And the relationship was properly set up.
For more information check out this Strapi post Understanding and using Relations in Strapi
Related
I have a simple mutation editPerson. It changes the name and/or description of a person specified by an id.
I use this little snippet to call the mutator from React components:
function useEditPerson(variables) {
const gqlClient = useGQLClient();
const personFragment = gql`fragment useEditPerson__person on Person {
id
name
description
}`;
return useMutation(gql`
${personFragment}
mutation editPerson($id: ID!, $description: String, $name: String) {
editPerson(id: $id, description: $description, name: $name) {
...useEditPerson__person
}
}
`, {
variables,
optimisticResponse: vars => {
const person = gqlClient.readFragment({
id: vars.id,
fragment: personFragment,
});
return {
editPerson: {
__typename: "Person",
description: "",
name: "",
...person,
...vars,
},
};
},
});
}
This works well enough unless either the name or description for the indicated person hasn't yet been queried and does not exist in the cache; in this case person is null. This is expected from readFragment - any incomplete fragment does this.
The thing is I really need that data to avoid invariant errors - if they're not in the cache I'm totally okay using empty strings as default values, those values aren't displayed anywhere in the UI anyway.
Is there any way to read partial fragments from the cache? Is there a better way to get that data for the optimistic response?
I guess you use the snippet in the form that has all the data you need. So, you can pass the needed data to your useEditPerson hook through the arguments and then use in optimistic response, and then you won't need to use gqlClient.
In a KeystoneJS GraphQL project I'm trying to create a new data object (an "Article") in the 'resolveInput' hook of another, existing, data object (a "Proposal" -- when a Proposal is approved, I create an Article based on that Proposals'data).
This worked fine using the Mongoose adapter, but I've tried to do it using the built in GraphQL API, using keystone.executeQuery and I get the following error:
My Article list has a relationship with one Proposal (I'm leaving out the other fields)
fields: {
proposal: {
isUnique: false,
type: fields_1.Relationship,
ref: 'Proposal',
access: {
create: true,
read: true,
update: false
}
}
}
and I create the new Article thus (I'm omitting some code)
hooks: {
resolvedInput: async params => {
const articleCreateInput = {
title: cleanTitle,
text: cleanText,
visible: HIDDEN,
proposal: {
connect: {
id: proposalId
}
}
};
const articleCreationResult = await keystone.executeQuery(createArticle, { variables: articleCreateInput });
}
}
As far as I can see this is the correct way to do it, using connect, connecting an existing item to one you are creating.
My query is
const createArticle = `mutation createArticle($data:ArticleCreateInput) {
createArticle(data:$data) {
id
title
visible
publishDate
}
} `;
and as far as I can see I'm following the schema correctly
I'm sure I'm making an obvious mistake but at the moment I don't see it -- and I'm not sure whether that mistake is a GraphQL mistake or a KeystoneJS mistake (or both).
i want to create a new graphql api and i have an issue that i am struggling to fix.
the code is open source and can be found at: https://github.com/glitr-io/glitr-api
i want to create a mutation to create a record with relations... it seems the record is created correctly with all the expected relations, (when checking directly into the database), but the value returned by the create<YourTableName> method, is missing all the relations.
... so so i get an error on the api because "Cannot return null for non-nullable field Meme.author.". i am unable to figure out what could be wrong in my code.
the resolver looks like the following:
...
const newMeme = await ctx.prisma.createMeme({
author: {
connect: { id: userId },
},
memeItems: {
create: memeItems.map(({
type,
meta,
value,
style,
tags = []
}) => ({
type,
meta,
value,
style,
tags: {
create: tags.map(({ name = '' }) => (
{
name
}
))
}
}))
},
tags: {
create: tags.map(({ name = '' }) => (
{
name
}
))
}
});
console.log('newMeme', newMeme);
...
that value of newMeme in the console.log here (which what is returned in this resolver) is:
newMeme {
id: 'ck351j0f9pqa90919f52fx67w',
createdAt: '2019-11-18T23:08:46.437Z',
updatedAt: '2019-11-18T23:08:46.437Z',
}
where those fields returned are the auto-generated fields. so i get an error for a following mutation because i tried to get the author:
mutation{
meme(
memeItems: [{
type: TEXT
meta: "test1-meta"
value: "test1-value"
style: "test1-style"
}, {
type: TEXT
meta: "test2-meta"
value: "test2-value"
style: "test2-style"
}]
) {
id,
author {
displayName
}
}
}
can anyone see what issue could be causing this?
(as previously mentioned... the record is created successfully with all relationships as expected when checking directly into the database).
As described in the prisma docs the promise of the Prisma client functions to write data, e.g for the createMeme function, only returns the scalar fields of the object:
When creating new records in the database, the create-method takes one input object which wraps all the scalar fields of the record to be
created. It also provides a way to create relational data for the
model, this can be supplied using nested object writes.
Each method call returns a Promise for an object that contains all the
scalar fields of the model that was just created.
See: https://www.prisma.io/docs/prisma-client/basic-data-access/writing-data-JAVASCRIPT-rsc6/#creating-records
To also return the relations of the object you need to read the object again using an info fragment or the fluent api, see: https://www.prisma.io/docs/prisma-client/basic-data-access/reading-data-JAVASCRIPT-rsc2/#relations
I'm using Gatsbyjs to build a blog and I can't use the onCreatePage API to pass data from my graphql query into page templates.
My query grabs data from Kentico Cloud and it looks like this.
{
allKenticoCloudTypeBlogPost{
edges{
node{
contentItems{
elements{
url_slug{
value
}
}
}
}
}
}
}
This is a valid query and it returns data that looks like this.
The problem comes in my gatsby-node.js file where I want to utilize this query to build out pages using my predefined template.
Specifically in the createPage method which looks like this.
result.data.allKenticoCloudTypeBlogPost.edges.map(({node}) => {
createPage({
path: `${node.contentItems.elements.url_slug.value}`,
component: path.resolve(`./src/templates/blog-post.js`),
context: {
slug: node.contentItems.elements.url_slug.value,
}
})
});
The error that displays is the following.
TypeError: Cannot read property 'url_slug' of undefined
gatsby-node.js:31 result.data.allKenticoCloudTypeBlogPost.edges.map
C:/Users/xxxx/Desktop/Marketing Repos/xxxx/gatsby-node.js:31:57
I decided to investigate doing a console.table on node.contentItems, as it appears as though the elements part is where it gets tripped up.
The result of console.table(node.contentItems) just before the createPage method is this.
It appears that node.contentItems has a member called url_slug rather than the elements member that I expected.
I thought I could then solve my problem by updating my createPage method call like so.
result.data.allKenticoCloudTypeBlogPost.edges.map(({node}) => {
console.table(node.contentItems);
createPage({
path: `${node.contentItems.url_slug.value}`,
component: path.resolve(`./src/templates/blog-post.js`),
context: {
slug: node.contentItems.url_slug.value,
}
})
});
But then I get an error saying
TypeError: Cannot read property 'value' of undefined.
I truly don't understand how I can do a table log and see the url_slug member, but then when I try to access it, it says that it's undefined. All while I know that my query is correct because I can run it in graphiQL and get back the exact data I expect.
Any help would be appreciated. Thank you.
In your query result, node.contentItems is an array, even though you're trying to access it as if it's an object:
path: `${node.contentItems.elements.url_slug.value}`,
^^^^^^^^
console.log(contentItems) // [ { elements: {...} }, { elements: {...} }, ... ]
I think your confusion probably stems from the way console.table display data. It's confusing if you don't already know the shape of your data. Your screenshot says, this object has 4 properties with index 0 -> 3 (so likely an array), each has one property called elements (listed on table header), which is an object with the only property url_slug.
I'm not familiar with KenticoCloud, but maybe your posts are nested in contentItems, in which case you should loop over it:
result.data.allKenticoCloudTypeBlogPost.edges.map(({node}) => {
node.contentItems.forEach(({ elements }) => {
createPage({
path: elements.url_slug.value,
context: { slug: elements.url_slug.value },
component: ...
})
})
});
Is there a reason you are wrapping node with curly brackets in your map argument?
You might have already tried this, but my first intuition would be to do this instead:
result.data.allKenticoCloudTypeBlogPost.edges.map(node => {
console.log(node.contentItems)
createPage({
path: `${node.contentItems.elements.url_slug.value}`,
component: path.resolve(`./src/templates/blog-post.js`),
context: {
slug: node.contentItems.elements.url_slug.value,
}
})
});
When I start my react-native app I wan't to query "everything" for an offline experience.
So I
query all {
groups {
...GroupF
}
persons {
...PersonF
}
}${PERSON_ITEM}${GROUP_ITEM}
PersonF and GroupF are fragments.
The first view has a list of groups, each person can belong to a group. When the user clicks on an group the query looks like:
persons($group: ID) {
persons(group: $group) {
...PersonsF
}
}${PERSON_ITEM}
But my cacheRedirects just does not reflect the same data as is returned.
I know this because i console.log out the response in my component wrapper (it looks excellent here)
but in my
const cache = new InMemoryCache({
cacheRedirects: {
Query: {
persons: (_, args, {getCacheKeys}) => {
// I have tried everything here but nothing maps correctly
// I have tried getCacheKey({__typename: 'Person', id: args.group})
// I have tried following the apollo documentation
// No luck, it just can't find the group
// Using the chrome dev tools I don't see persons having groups
const a = getCacheKey({__typename: 'Person', id: args.group});
// Console.log(a) is:
// {generated: false, id: "Person:9", type: "id", typename "Person"}
}
}
}
});
Do you have any suggestions on how I can write a proper cache redirects persons query?
Help really really really appreciated
|1| https://www.apollographql.com/docs/react/advanced/caching.html#cacheRedirect
This was caused by the fact we used the id field in the Person, since we stoped using the field it works perfectly.