Virtual field breaks AdminUI
See original GitHub issueI set up a virtual field relatedArticles
in my Article
field
relatedArticles: {
schemaDoc: 'Articles related to this article',
type: Virtual,
graphQLReturnType: '[Article]',
resolver: virtualRelatedFieldsResolver
}
the resolver for which is as follows
import { sampleSize } from 'lodash';
import log from '../../util/log';
import { PUBLISHED } from '../../lists/Article';
const NUMBER_OF_RELATED_ARTICLES = 3;
const ARTICLE_QUERY = `query Article($where:ArticleWhereUniqueInput!) {
Article(where:$where){
url
topic {
topic
}
}
}`;
const ARTICLES_QUERY = `query allArticles($where:ArticleWhereInput) {
allArticles(where:$where){
title
url
cardDescription
}
}`;
type articleQueryReturn = {
Article: {
data: any;
errors: any;
[key: string]: any;
};
};
type articlesQueryReturn = {
allArticles: {
data: any;
errors: any;
[key: string]: any;
};
};
export default async (item, args, context) => {
try {
log.info('entering related articles', item, args);
const id = item?.id;
if (!id) throw new Error('getRelatedArticlesVirtualField: No ID passed');
if (typeof id !== 'string') throw new Error('getRelatedArticlesVirtualField: ID passed is not a string');
// get current article based on ID passed
const skipAccessControl = true;
// const result = await keystone.executeQuery(ARTICLE_QUERY, { variables: { where: { id } } });
const { data, errors }: { data: articleQueryReturn; errors: any } = await context.executeGraphQL({
query: ARTICLE_QUERY,
variables: { where: { id } }
});
if (errors) throw new Error(`getRelatedArticlesVirtualField: Error getting article from ID: ${errors.toString()}`);
const article = data?.Article;
// if this article has no topics, punt
if (!article?.topic || !article?.topic?.length) throw new Error('getRelatedArticlesVirtualField: ID does not return any article');
// get the topics from this article
const selectedTopics = article.topic.map((topicObj) => topicObj.topic);
// find all related articles
/* const result2 = await keystone.executeQuery(ARTICLES_QUERY, {
variables: { where: { status: PUBLISHED, topic_some: { topic_in: selectedTopics } } }
});*/
const { data: data2, errors: errors2 }: { data: articlesQueryReturn; errors: any } = await context.executeGraphQL({
context: context.createContext({ skipAccessControl }),
query: ARTICLES_QUERY,
variables: { where: { status: PUBLISHED, topic_some: { topic_in: selectedTopics } } }
});
// if there is a problem getting these then punt
if (errors2) throw new Error(`getRelatedArticlesVirtualField: Error getting related articles: ${errors.toString()}`);
if (!data2?.allArticles)
throw new Error(
`getRelatedArticlesVirtualField: error with fetching related articles from ID: no articles returned with these topics:
${selectedTopics}`
);
const relatedArticles = data2?.allArticles;
// remove the current article
const filtered = relatedArticles.filter((relatedArticle) => relatedArticle.url !== article.url);
// now get NUMBER_OF_RELATED_ARTICLES randomly from this array
return sampleSize(filtered, NUMBER_OF_RELATED_ARTICLES);
} catch (error) {
log.error(`error in getting related articles ${error.toString()}`);
return [];
}
};
and this worked fine. However when I went to the AdminUI and clicked on an article I got an error
Couldn't find an Article matching that ID
when I checked the browser console log I saw
and when I checked the Keystone logs I found
query getItem { .. }
⤷ inspect @ http://localhost:4545/admin/graphiql/go?id=1539bcba2c6b7950ea38ca56b7276dd3b674344a
{"level":50,"time":1593432803526,"pid":13566,"hostname":"AGOMA1002.local","name":"graphql","message":"Field \"relatedArticles\" of type \"[Article]\" must have a selection of subfields. Did you mean \"relatedArticles { ... }\"?","locations":[{"line":38,"column":5}],"uid":"ckc0gr0060001guwk6h1x5m2l","name":"ValidationError","stack":"Object.Field (node_modules/graphql/validation/rules/ScalarLeafs.js:45:31)\nObject.enter (node_modules/graphql/language/visitor.js:324:29)\nObject.enter (node_modules/graphql/language/visitor.js:375:25)\nvisit (node_modules/graphql/language/visitor.js:242:26)\nObject.validate (node_modules/graphql/validation/validate.js:73:24)\nvalidate (node_modules/apollo-server-core/dist/requestPipeline.js:221:34)\nObject.<anonymous> (node_modules/apollo-server-core/dist/requestPipeline.js:118:42)\nGenerator.next (<anonymous>)\nfulfilled (node_modules/apollo-server-core/dist/requestPipeline.js:5:58)\nrunMicrotasks (<anonymous>)\n","v":1}
{"level":30,"time":1593432803527,"pid":13566,"hostname":"AGOMA1002.local","req":{"id":31,"method":"POST","url":"/admin/api","headers":{"host":"localhost:4545","connection":"keep-alive","content-length":"812","pragma":"no-cache","cache-control":"no-cache","accept":"*/*","user-agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1","content-type":"application/json","origin":"http://localhost:4545","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"http://localhost:4545/admin/articles/5eeb2fb96103015885720c90","accept-encoding":"gzip, deflate, br","accept-language":"en-GB,en-US;q=0.9,en;q=0.8,es;q=0.7,de;q=0.6","cookie":"keystone.sid=s%3Aa5X5eLDp8NYH05e5GOrVm-2GcT58ISr0.9RiZ2s3BflE4yNRCa1rGZlbMKhHyDKRo5dUniW3%2BnRk"},"remoteAddress":"::1","remotePort":53023},"res":{"statusCode":400,"headers":{"x-powered-by":"Express","x-keystone-app-version":"1.0.0","access-control-allow-origin":"http://localhost:4545","vary":"Origin","access-control-allow-credentials":"true","content-type":"application/json; charset=utf-8","content-length":"1622","etag":"W/\"656-8Ep+1ytrsZl4HYFFDtrb/HiYjiw\""}},"responseTime":5,"msg":"request completed","v":1}
which led to the query
query getItem($id: ID!) {
Article(where: {id: $id}) {
_label_
id
title
url
text
author {
id
_label_
__typename
}
articleType
cardDescription
cardImage {
id
_label_
__typename
}
headerImage {
id
_label_
__typename
}
topic {
id
_label_
__typename
}
status
publishDate
readTime
proposal {
id
_label_
__typename
}
relatedArticles
updatedBy {
id
_label_
__typename
}
createdBy {
id
_label_
__typename
}
updatedAt
createdAt
__typename
}
}
If I removed the GraphQLReturnType
from my virtual field description, the AdminUI worked but the GraphQL API broke, since it was now assuming that the relatedFields
were a string, not an array of Articles.
Issue Analytics
- State:
- Created 3 years ago
- Comments:7 (2 by maintainers)
Top Results From Across the Web
Virtual field breaks AdminUI · Issue #3210 · keystonejs/keystone
I set up a virtual field relatedArticles in my Article field relatedArticles: { schemaDoc: 'Articles ... Virtual field breaks AdminUI #3210.
Read more >Lesson 2: Creating relationships - Keystone 6 Documentation
Learn how to connect two content types to each another and configure how you make those connections in Admin UI.
Read more >Control Break Identification and User Field Identification ...
The Control Break Identification subpanel is used to define the location within a report where separator pages are to be inserted for control...
Read more >Customize the Django Admin With Python
In this tutorial, you'll learn how to customize Django's admin with Python. ... Install Django inside a clean virtual environment:.
Read more >Tips on Breaking into the Admin Field
The first step to breaking into the field is understanding what makes a good administrative professional. In order to accurately represent how ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I would suggest – if it’s accurate – that the documentation say something like
“For more complex types you must also define a graphQLReturnFragment as well as extendGraphQLTypes.”
Keystone 5 has officially moved into active maintenance mode as we push towards the next major new version Keystone Next, you can find out more information about this transition here.
In an effort to sustain the project going forward, we’re cleaning up and closing old issues such as this one. If you feel this issue is still relevant for Keystone Next, please let us know.