question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Virtual field breaks AdminUI

See original GitHub issue

I 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

image

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:closed
  • Created 3 years ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
ra-externalcommented, Jun 30, 2020

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.”

0reactions
bladeycommented, Apr 8, 2021

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.

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found