GraphQL register new Type wiring with argument to data fetcher - graphql

Having a GraphQL schema:
type TypeA {
id: ID,
name: String,
other: TypeC
}
type TypeB {
id: ID,
name: String,
other: TypeC
}
How should I implement TypeC wiring independently from source object type? I know I can do:
RuntimeWiring.newRuntimeWiring()
.type(TypeRuntimeWiring.newTypeWiring("TypeA")
.dataFetcher("other", dataFetcher_typeC.get())
.type(TypeRuntimeWiring.newTypeWiring("TypeB")
.dataFetcher("other", dataFetcher_typeC.get())
.build()
but then the data fetcher is dependant on a source object type:
DataFetcher<CompletableFuture<Collection<TypeC>>> get() {
return dataFetchingEnvironment -> {
<??> sourceObj = dataFetchingEnvironment.getSource();
return getObject(sourceObj.someProperty);
};
}
Given both POJOs (TypeA and TypeB) have reference field to TypeC, how to resolve TypeC field by given reference, not source object?

I have actually figured out two possible solutions to the problem:
When defining new wiring, get source object and from it the field. Call dataFetcher method with parameter, like regular java method:
Inside data fetcher get field name from DataFetcherEnvironment. Use reflection to get field from source object
Example #1:
RuntimeWiring.newRuntimeWiring()
.type(TypeRuntimeWiring.newTypeWiring("TypeA")
.dataFetcher("other", environment -> {
TypeA sourceObj = environment.getSource();
return dataFetcher_typeC.get(sourceObj.other)})
.type(TypeRuntimeWiring.newTypeWiring("TypeB")
TypeB sourceObj = environment.getSource();
return dataFetcher_typeC.get(sourceObj.other)})
.build()
Example #2:
DataFetcher<CompletableFuture<Collection<TypeC>>> get() {
return dataFetchingEnvironment -> {
Field declaredField = dataFetchingEnvironment.getSource().getClass()
.getDeclaredField(dataFetchingEnvironment.getField().getName());
declaredField.setAccessible(true);
String value = (String) declaredField.get(dataFetchingEnvironment.getSource());
return getObject(sourceObj.someProperty);
};
}
Second option looks better but still unsure if this is correct approach.

From the documentation here
the dataFetchingEnvironment provides getExecutionStepInfo() method which returns the ExecutionStepInfo object. From there, you can get the parent information.
ExecutionStepInfo executionStepInfo = environment.getExecutionStepInfo();
ExecutionStepInfo parentInfo = executionStepInfo.getParent();
GraphQLObjectType parentType = (GraphQLObjectType) parentInfo.getUnwrappedNonNullType();
// parentType.getName() returns you "TypeA" or "TypeB"

Related

GraphQL query with nested query passing parameters to non scalar type arguments

I have a current Query type defined like this:
type BoxItems {
total: Number,
boxItems: [BoxItem]
}
type Box {
boxItemUuid: UUID!
boxItems:(page: Number, pageSize: Number): BoxItems
}
extend Query {
boxes(input: SomeInputType): [Box]
boxItems(boxItemUuid: UUID!, page: Number, pageSize: Number): BoxItems
}
Which is then called by client like:
query BoxesQuery($input: SomeInputType){
boxes(input:$input){
boxItems:(pageSize:1){
total
}
}
}
In this case a boxItems resolver function is still able to access boxItemUuid in the args object. My question is what if I decide to create input types for my boxItems Query type. For instance, lets say boxItemUuid was now defined in FilterInfo type
boxItems(pageInfo: PageInfo, filter: FilterInfo): BoxItems
How would I go about defining the query client BoxesQuery, to pass boxItemUuid as a field on the FilterInfo type? Is this even possible? Is it bad practice for query types to include non scalar type parameters?
I didn't realize the resolver handler, which was not included in my question was checking parent, and args object for a particular parameter. So the answer here is to grab parameter from parent object
resolver(parent, args, context){
const boxItemUuid = parent.boxItemUuid || args.boxItemUuid;
}

How to find path to a field in a graphql query

I am very new to graphql. I have a following graphql query for an example:
query pets {
breed(some arguments)
{
name
items
{
owner(some arguments)
{
items
{
ID
ownerSnumber
country
address
school
nationality
gender
activity
}
}
name
phoneNumber
sin
}
}
}
Is it possible to parse a gql query and get the path of a field in the query?
For example I would like to get the path of 'ID'. For example from the above query, is it possible to get the path where the ID is: owner.items.ID
With https://graphql.org/graphql-js/ it exposes a fourth argument called resolve info. This field contains more information about the field.
Have a look at GraphQLObjectType config parameter type definition:
With a good start from the earlier answer, relying on the ResolveInfo you could do something like a recursive check going from child to parent:
export const getFieldPath = (path: Path): string => {
if (!path.prev) return `${path.key}`
return `${getFieldPath(path.prev)}.${path.key}`
}
And later in your resolver you could use it like:
const myFieldResolver = (parent, args, ctx, info) => {
const pathOfThisResolversField = getFieldPath(info.path)
// use your pathOfThisResolversField
return yourFieldResolvedData
};
Worth noting though, the solution above will include every node all the way to the query root, rather than just the ones you mentioned owner.items.ID

Overriding "root" object value of GraphQL Union/Interface type

I have an Apollo GraphQL service that delegates to an internal gRPC service. This service has an endpoint which returns a message that contains a oneof, which I'm mapping to a Union in GraphQL.
This is straightforward, but there's a fair degree of boilerplate involved when implementing the resolvers. Suppose I have the following protobuf message definition:
message MyUnionMessage {
oneof value {
UnionType1 type1 = 1;
UnionType1 type2 = 3;
UnionType1 type3 = 4;
}
}
message UnionType1 {<type 1 props>}
message UnionType2 {<type 2 props>}
message UnionType3 {<type 3 props>}
My corresponding GraphQL schema looks something like this:
union MyUnionType = UnionType1 | UnionType2 | UnionType3
type UnionType1 {<type 1 props>}
type UnionType1 {<type 2 props>}
type UnionType1 {<type 3 props>}
In the javascript binding for gRPC, a MyUnionMessage object will have two properties: value which is a string indicating which type of value is contained, and a property named for the type. So, if I had a MyUnionMessage containing a UnionType2, for example, the object would look like this:
{
value: 'type2',
type2: {...}
}
This is nice for implementing __resolveType, since I can do a simple switch on the value in value, but I then have to write a resolver for all of the fields of all of the concrete types.
What I'm looking for is to be able to so something like this:
resolvers = {
MyUnionType: {
__resolveType(obj) {
switch(obj.value) {
case 'type1': return 'UnionType1';
case 'type2': return 'UnionType2';
case 'type3': return 'UnionType3';
default: return null;
},
__resolveValue(obj) {
return obj[obj.value];
},
},
};
Basically, I want to write a "resolver" at the level of the generic union (or interface) type that transforms the object before it's passed to the concrete resolver.
Is such a thing possible?
I'd wager that this sort of scenario is typically solved by transforming the data before it hits the __resolveType logic. For example, say you had a Query field that returned a list of MyUnionType. Your resolver for that field might look something like:
function resolve (arr) {
return arr.map(obj => {
return {
...obj[obj.value]
type: obj.value // or whatever field name that won't cause a collision
}
})
}
You then switch on type inside of __resolveType and you're good to go. Of course, that means if you have multiple fields that return a MyUnionType, you'll want to extract that logic into a utility function that can be used by each resolver.
I don't think there's not really a way to do what you're trying to do with the existing API. You could, of course, do something like this:
const getUnionType(obj) {
switch(obj.value) {
case 'type1': return 'UnionType1';
case 'type2': return 'UnionType2';
case 'type3': return 'UnionType3';
default: {
throw new Error(`Unrecognized type ${obj.value}`)
}
}
}
const resolvers = {
MyUnionType: {
__resolveType(obj) {
const type = getUnionType(obj)
Object.assign(obj, obj[obj.value])
return type
},
},
};
This works, but keep in mind it is a bit fragile since it assumes resolveType will always get the same root value as the resolve function, which could hypothetically change in the future.

Subtypes Supertypes in go

Coming from OOP paradigms and porting a code from an OOP language, I come across a problem now which is solved in OOP via abstraction so I'm wondering how can I approach the following problem in Go which follows composition instead of inheritance.
In this scenario my ValueObjects (DTO, POJO etc.) are composed of other ValueObjects. I'm populating them through web service calls that returns json so basically my functions/method calls are common for all types and subtypes.
My super type EntityVO
type EntityVO struct {
EntityName string
EntityType string
PublicationId string
Version string
}
A subtype 1 composed with EntityVO
type ArticleVO struct {
EntityVO
ContentSize string
Created string
}
subtype 2 composed with EntityVO with it's own unique set of fields
type CollectionVO struct {
EntityVO
ProductId string
Position string
}
I'm calling web services to retrieve data and populate these VOs.
Earlier I had one function to call the web service and populate the data but now I'm duplicating the code for each VO.
type Article struct{}
func (a *Article) RequestList(articleVO *valueObject.ArticleVO) (*valueObject.ArticleVO, error) {
// some code
}
Duplicating the same code but changing the signature.
type Collection struct{}
func (c * Collection) RequestList(collectionVO *valueObject.CollectionVO) (*valueObject.ArticleVO, error) {
// some code - duplicate same as above except method signature
}
and I've several entities and just because my VO's are different I'm forced to duplicate the code and cater to each type of VO I've. In OOP sub types can be passed to a function accepting super types but not in go, so wondering how it should be done so I don't end up duplicated code that's different in signature only?
Any advice for a better approach in this kind of scenario?
This is where golang interfaces can shine.
It's worth noting, however, that it's difficult to write subclass/inheritance code in golang. We'd prefer thinking of it as composition.
type EntityVO interface {
GetName() string
SetName(string) error
GetType() string
...
}
type EntityVOImpl struct {
EntityName string
EntityType string
PublicationId string
Version string
}
func (e EntityVOImpl) GetName() string {
return e.EntityName
}
...
type ArticleVOImpl struct {
EntityVOImpl
ContentSize string
Created string
}
type CollectionVOImpl struct {
EntityVO
ProductId string
Position string
}
// CODE
func (e *Entity) RequestList(entityVO valueObject.EntityVO) (valueObject.EntityVO, error) {
// some code
}
In addition, as long as your interface files are shared, I don't think there should by any problem sending/marshalling/unmarshalling the structs over the wire.
The second parameter of json.Unmarshal is a "universal" interface{} type. I think similar approach is applicable to your case.
Define data type for storing web service properties which may differ for each entity, e.g.
type ServiceDescriptor struct {
URI string
//other field/properties...
}
Function for populating the entity may look like
func RequestList(desc *ServiceDescriptor, v interface{}) error {
//Retrieve json data from web service
//some code
return json.Unmarshal(data, v)
}
You can call the function to populate different type of entities, e.g.
desc := &ServiceDescriptor{}
article := ArticleVO{}
desc.URI = "article.uri"
//...
//You must pass pointer to entity for 2nd param
RequestList(desc, &article)
collection := CollectionVO{}
desc.URI = "collection.uri"
//...
//You must pass pointer to entity for 2nd param
RequestList(desc, &collection)

Defining a MongoDB Schema/Collection in mgo

I want to use mgo to create/save a MongoDB collection. But I would like to define it more extensively (for e.g to mention that one of the attribute is mandatory, another one is of an enum type and has a default value).
I have defined the struct like this, but don't know how to describe the constraints on it.
type Company struct {
Name string `json:"name" bson:"name"` // --> I WANT THIS TO BE MANDATORY
CompanyType string `json:"companyType" bson:"companyType"` // -->I WANT THIS TO BE AN ENUM
}
Is this possible to do in mgo, like how we can do it in MongooseJS?
mgo isn't an ORM or a validation tool. mgo is only an interface to MongoDB.
It's not bad to do validation all by yourself.
type CompanyType int
const (
CompanyA CompanyType = iota // this is the default
CompanyB CompanyType
CompanyC CompanyType
)
type Company struct {
Name string
CompanyType string
}
func (c Company) Valid() bool {
if c.Name == "" {
return false
}
// If it's a user input, you'd want to validate CompanyType's underlying
// integer isn't out of the enum's range.
if c.CompanyType < CompanyA || c.CompanyType > CompanyB {
return false
}
return true
}
Check this out for more about enums in Go.

Resources