graphql-zeus icon indicating copy to clipboard operation
graphql-zeus copied to clipboard

Parsed schema is broken

Open grischaerbe opened this issue 3 years ago • 13 comments

I'm evaluating possibilities and options to interact with an existing GraphQL API that is provided by a CMS called Statamic Pro. On running zeus with this npm command: zeus https://someurl.com/graphql ./ --ts the contents of the output const.ts are broken in several places:

// … other parts of the file
export const ReturnTypes: Record<string,any> = {
// … non-broken lines
	GlobalSetInterface:{
,
		handle:"String",
		site:"Site",
		title:"String"
	},
	PageInterface:{
,
		entry_id:"ID",
		id:"ID",
		permalink:"String",
		title:"String",
		url:"String"
	},
	TermInterface:{
,
		edit_url:"String",
		id:"ID",
		permalink:"String",
		slug:"String",
		taxonomy:"Taxonomy",
		title:"String",
		uri:"String",
		url:"String"
	},
// … non-broken lines
}

the corresponding parts of the schema look like this:

…
interface GlobalSetInterface {
    handle: String!
    site: Site!
    title: String!
}

interface PageInterface {
    entry_id: ID
    id: ID!
    permalink: String
    title: String
    url: String
}

interface TermInterface {
    edit_url: String!
    id: ID!
    permalink: String
    slug: String!
    taxonomy: Taxonomy!
    title: String!
    uri: String
    url: String
}
…

This also leads to a broken index.ts file:

export type ModelTypes = {
    ["AssetInterface"]: ModelTypes["Asset_Assets"] | ModelTypes["Asset_Images"];
	["EntryInterface"]: ModelTypes["Entry_Articles_Articles"] | ModelTypes["Entry_Authors_Authors"] | ModelTypes["Entry_Issues_Issues"];
	["GlobalSetInterface"]: ;
	["PageInterface"]: ;
	["TermInterface"]: ;
	["Sets_Content"]:ModelTypes["BardText"] | ModelTypes["Set_Content_Vimeo"];
	["AssetContainer"]: {
		handle:string,
	title:string
};

I'm running Node v16.9.1, typescript 4.4.3. The entire schema is available here: https://www.codepile.net/pile/vl0p0Zl0 The output of const.ts: https://www.codepile.net/pile/N43knP4a The output of index.ts: https://www.codepile.net/pile/PKzP408j

I'm happy to provide more info to assist in debugging this. I'd love to use zeus, it looks great.

grischaerbe avatar Sep 12 '21 23:09 grischaerbe

Hi! I can fix this but you should not be able to use the schema either. You have interfaces that are left unused, so if the query returns interface that is not implemented anywhere, it is hard to generate correct typings. I do not know what tool you are using but the schema it's generating is against the spec and incorrect.

As a workaround we can add __typename: never to those incorrect interfaces so they don't break the code generation @grischaerbe

aexol avatar Sep 13 '21 11:09 aexol

@aexol Thanks for your effort & the clarification that the schema is against the spec, I was already suspecting that. The schema is generated automatically based on the setup of the CMS, the underlying library that is handling the heavy lifting of providing the GraphQL API – including the schema – is https://github.com/rebing/graphql-laravel. I'm not that much into the spec of GraphQL schemas but if I understand you correctly unused interfaces (like DateRange) are not allowed? Is that related to the broken code generation? Maybe it's a good idea to strip out these unused types beforehand.

grischaerbe avatar Sep 13 '21 11:09 grischaerbe

Fixed in 3.1.9, but I still don't know what you can do with it.

aexol avatar Sep 13 '21 11:09 aexol

@grischaerbe

aexol avatar Sep 13 '21 11:09 aexol

It means that when you return an interface, you return one of types implementing the interface. If no types are present then the resolver should not return anything

aexol avatar Sep 13 '21 11:09 aexol

Thanks again for your effort and the quick fix @aexol. I'm not sure if I understand you correctly. Is it that the schema contains types that are not implemented anywhere or that the ReturnType includes type names that don't have types? I can see that with 3.1.9 the type GlobalSetInterface includes a __typename:never (so I guess by that it's being marked as unused?) but it is actually the ReturnType of the queries globalSet and globalSets.

grischaerbe avatar Sep 13 '21 13:09 grischaerbe

Interface is only valid when implemented by types

aexol avatar Sep 14 '21 13:09 aexol

So when interface Animal is implemented by Cat Pig Dog it's __typename is __typename: "Cat" | "Pig" | "Dog"

aexol avatar Sep 14 '21 13:09 aexol

Ah, i see. So e.g. the interface GlobalSetInterface has not been implemented by any type but is marked as the return type of the query globalSets which renders the schema as against the GQL spec. Got it! I'll report back to the Statamic people. Thanks a ton, learned something today!

grischaerbe avatar Sep 14 '21 13:09 grischaerbe

Interface is only valid when implemented by types

Is this in the spec? Where?

jasonvarga avatar Sep 14 '21 14:09 jasonvarga

The interface type should have some way of determining which object a given result corresponds to. Once it has done so, the result coercion of the interface is the same as the result coercion of the object. @jasonvarga btw we are talking about __typename generated I think I can find the solution that will satisfy both worlds and allow for interface to be returned with __typename: "InterfaceNameHere" if that will help @grischaerbe I can make that change as I don't care how invalid interface ar transformed. What do you both think?

aexol avatar Sep 14 '21 20:09 aexol

@jasonvarga @grischaerbe

aexol avatar Sep 17 '21 08:09 aexol

Sorry I'm not familiar with this package or typescript but that sounds good to me.

jasonvarga avatar Sep 17 '21 13:09 jasonvarga