-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
redefine type references api #400
Conversation
@bbakerman @dminkovsky |
TL;DR I suggest you do away with My original implementation was akin to this one, but there were specific reasons I went the way I did:
Instead, I opted to keep type safety ( Whatever path you choose to take, I'd strongly advise not to give incomplete view of registered interfaces (or possible object types for unions) to the client during building as this is a surprising behavior (could cause hard-to-notice bugs in existing client code). It is much better to force the client to consolidate the references and real types themselves than not to be able to do this at all and have inconsistent view. Maybe expose an additional method that returns everything as I'd even go as far as to suggest a completely opposite route: remove |
I think you should update the README.md and the ReadmeExamples.java to explain this decision. The original update I made was to stop people failing into the trap of how to type reference. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I would add a readme example so consumers know how to use it
import graphql.schema.TypeResolver; | ||
import graphql.schema.TypeResolverProxy; | ||
import graphql.language.*; | ||
import graphql.schema.*; | ||
import graphql.schema.idl.errors.SchemaProblem; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which import rules you want to run in this library.
I personally find "import all" better but your tooling is not doing that clearly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bbakerman what do you mean with "import all"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I must say this part is handled by IDEA and it was not really intentional :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bbakerman Ok ... I know what you mean: these wildcards imports are caused by wrong idea settings: I never want wildcard imports.
@kaqqao Thanks for your input! I think you have a point there: I must agree that I don't like this part either: public List<GraphQLInterfaceType> getInterfaces() {
if (this.interfaces == null) {
return this.tmpInterfaces
.stream()
.filter(TypeOrReference::isType)
.map(TypeOrReference::getType)
.collect(Collectors.toList());
}
return new ArrayList<>(interfaces);
} I will definitely think about it more, before it will get merged. About the type safety part: I think the current implementation doesn't provide any, even if it looks like it: |
@kaqqao After thinking about it more I changed it so that The downside now is that the return type of the Methods needed to be a more generic: e.g. |
this(name, description, fieldDefinitions, interfaces, null); | ||
} | ||
|
||
public GraphQLObjectType(String name, String description, List<GraphQLFieldDefinition> fieldDefinitions, | ||
List<GraphQLInterfaceType> interfaces, ObjectTypeDefinition definition) { | ||
List<GraphQLOutputType> interfaces, ObjectTypeDefinition definition) { | ||
assertValidName(name); | ||
assertNotNull(fieldDefinitions, "fieldDefinitions can't be null"); | ||
assertNotNull(interfaces, "interfaces can't be null"); | ||
assertNotNull(interfaces, "unresolvedInterfaces can't be null"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assertNotNull(interfaces, "unresolvedInterfaces can't be null");
This is a leftover from the first implementation, should be deleted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks
This was exactly my approach at some point as well. It is correct (in the sense it always gives correct information), so I'm ultimately fine with it. Just out of curiosity I must ask: if these problems stem from the fact the reference API wasn't originally intended to be used the way it is being used now, have you considered redesigning the whole thing i.e. making all problematic types like |
@kaqqao Yes, I thought about redesigning the whole hierarchy, but my main focus was:
I tried to redesign it in a better/cleaner way, but was just too much for now. So this is the best I came up with and I'm ok with it for now. Thanks a lot for your feedback! |
So are we happy to merge this? |
@bbakerman Documentation update is still missing ... after that I will merge it. |
Removes the TypeReference class in favour of the already existing GraphQLTypeReference.
…s` and `getTypes` at the same time.
5483e53
to
c3524d6
Compare
Breaking change (Details about the breaking stuff below)
This tries to streamline and simplify how to provide type references (resolved when the schema is built) to a Schema.
A bit background:
I originally restricted the
GraphQLTypeReference
to be used just forGraphQLOutputTypes
, because I thought recursive (circular) type definitions would not be allowed.This was clarified in graphql/graphql-spec#189, that it is indeed allowed.
After that
GraphQLTypeReference
was changed to also implementedGraphQLInputType
. See PR #172.PR #172 added also some static factory methods which returned special internal subclasses which would be for example of type
GraphQLInterfaceType
AND marked as type resolver:This enabled type referenced to be used everywhere, but it added a second way for type references handling:
Instantiate
GraphQLTypeReference
or use these.references
factory methods, whenGraphQLTypeReference
could not be used.This is not really a nice API: two very different ways how to achieve the same thing.
This PR removes the static factory methods and makes
GraphQLTypeReference
useable everywhere: it adds new methods toGraphQLObjectType
andGraphQLUnionType
so thatGraphQLTypeReference
s can be provided:e.g.:
This methods are unfortunately necessary because
GraphQLObjectType
expects concreteGraphQLInterface
instances and there is no interface forGraphQLInterface
(a bit ironic). IfGraphQLInterface
would be an interface we could have provided two different implementations: one interface definition and one type reference.Breaking changes and migration:
The
.reference
factory methods inGraphQLInputObject
,GraphQLInterfaceType
andGraphQLObjectType
are removed.Instead of using them just create a new
GraphQLTypeReference
with new same argument.Also the return types of
GraphQLObjectType.getInterfaces
is nowList<GraphQLOutputType>
instead ofList<GraphQLInterface>
andGraphQLUnionType.getTypes()
is nowList<GraphQLOutputType>
instead ofList<GraphQLObjectType>
. This is because they can returnGraphQLTypeReferences
before they are resolved.