How to reference Context object in provided class methods? - graphql

We are using graphql-java and with com.coxautodev.graphql.tools.SchemaParser (from graphql-java-tools) we are creating executable schema - and it works just fine. Now we need to add user information and propagate it to our graphql method logic. The obvious approach is to use "context" object.
So, in mutations.graphql file there is:
type Mutations
createGroup(input: CreateGroupInput): IdRequest
...
On the other hand, there is a Java class with the corresponding method:
IdRequest createGroup(CreateGroupInput input) {
...
}
Then, when calling graphql.GraphQL.execute(myQuery, contextObject) how to read this contextObject into Java method above?

The thing I was looking for is DataFetchingEnvironment (see Fetching data).
The "contextObject" can then be retrieved in Java class by adding DataFetchingEnvironment as a last argument, like:
IdRequest createGroup(CreateGroupInput input, DataFetchingEnvironment environment) {
Object contextObject = environment.getContext();
...
}

Related

Custom serialization of specific return type for DataFetcher

I am using Spring for GraphQL (version 2.7.0-M1).
In my domain model, a lot of properties return an object Foo. This object must be serialized to a String based on data available from GraphQlContext. So the schema looks like:
type Parent {
code: String!
foo: String
...
}
It is easy to do this with #SchemaMapping for a specific parent type.
#SchemaMapping(typeName = "Parent", field = "foo")
public String foo(Parent parent, DataFetchingEnvironment env) {
var context = env.getGraphQlContext();
return ...
However, this is not very DRY. I am looking for a way to have this code at one place, like a custom scalar.
Is there a way to do this with spring-graphql / graphql-java?
Example
An example is a Localized<T> object we use. For instance a Product instance has Localized<String> properties for title and description (and more).
For the GraphQL query we can set the context, part of the context is the Locale. For all Localized property values the value can be converted to the string value for the locale. We are looking for a way to do this automagically. Otherwise it creates a lot of boiler plate code
Would #ContextValue help here? This would remove a bit of boilerplate from your controller handlers.
#SchemaMapping(typeName = "Parent", field = "foo")
public String foo(Parent parent, #ContextValue Foo foo) {
If you'd like something more involved, I think you should elaborate on the exact relationship between an attribute of one or multiple types in your schema, and some random value in the context.
Maybe you could come up with some concrete example here?

Deserialize nested Kotlin object in springMVC

I'm trying to deserialize a complex GET request into a structure of nested objects.
The GET requests looks like:
curl 'localhost:8080/?id=1&inner.id=1'
and the code should look like this:
class RootObj(val id: Int, inner: InnerObject)
class InnerObject(val id: Int)
#RestController
class SearchController {
#GetMapping(path = ["/"])
fun getRoot(rootObj: RootObj): String {
return "ok"
}
}
This doesn't work out of the box I guess because spring doesn't know how properly create this nested structure.
Parameter specified as non-null is null: [...] parameter inner","path":"/"}%
Is there a way to overcome this problem? Maybe providing a totally custom deserializer code?
As alternative solution, I guess I could flatten the object hierarchy but for doing so I must be able to map a query parameter like inner.id to a field named innerId
Spring can actually map the query params to the custom object directly, but you need to provide defaults to the params of the custom object constructor.
So you need to define your classes as below for it to work
class RootObj(val id: Int = 0, val inner: InnerObject = InnerObject(0))
class InnerObject(var id: Int = 0)
Do note that the id field of InnerObject would have to be declared as var for Spring to be able to map it. Then curl 'localhost:8080/?id=1&inner.id=1' would work fine.

Passing json "data" array in Retrofit 2

I'm trying retrofit 2 for the first time and I have no idea how to tell it to get "Category" objects from an jsonarray named "data".
Method 1
If I do it like this it fails:
#GET("category")
Call<List<Category>> listCategories();
Method 2
But when I make a new model, called "Categories", which holds a List and is annotated with #SerializedName("data"), it works flawlessly.
#GET("category")
Call<Categories> listCategories();
My Question
Should I annotate something in the interface, like this
#GET("category")
#Annotation to look inside "data"
Call<List<Category>> listCategories();
Or should I annotate my "Category" model to tell Retrofit (or GSON)
that it lives inside the json array "data"?
JSON
{"data":[{"id":1,"name":"Fist Name","parent":0},{"id":2,"name":"Second Name","parent":1}]}
Method 2 Is correct and we use it when we dont want to use/define the json response object/arrays key names(field names). instead provide our own. Eg. In below code List object name is items but while Serialization and Deserialization it uses, what you have defined in #SerializedName annotation that is data.
public class Categories {
//solution 1
List<Category> data;//object name must match with the json response
//solution 2
#SerializedName("data")
List<Category> items;
}
Should I annotate something in the interface
No. There is no such annotation available and everything you can do is only in Response type class.

mocking a method with parameter as LIST type

I want to mock the below mentioned method.
public class MockClass {
public boolean ToBeMocked(Cinput, Coutput, List<CIOChain<Cinput, Coutput>>)
}
What should be in place of ?? in below mentioned code ?
Easymock.expect(MockClassObject.ToBeMocked(Cinput.class, Coutput.class, ??)).andReturn(true);
At the Class level, all List interfaces are the same regardless of the generic type, due to type erasure; they are only different at compile time.
So it's just List.class in place of ??.
That is,
Easymock.expect(MockClassObject.ToBeMocked(Cinput.class, Coutput.class, List.class)).
andReturn(true);
In the scope of mocking, you should really be specifying the objects that you expect to be passed to that method, like:
Easymock.expect(MockClassObject.ToBeMocked(cInputObj, cOutputObj, listObj)).
andReturn(true);
If for some reason you can't do that, you can use isA/anyObject variants:
Easymock.expect(MockClassObject.ToBeMocked(isA(Cinput.class), isA(Coutput.class), isA(List.class))).
andReturn(true);

In Spring MVC 3, how do I bind an object to a query string when the query string parameters don't match up with the object fields?

A 3rd party is sending me part of the data to fill in my domain object via a query string. I need to partially fill in my domain object, and then have the user fill in the rest via a form. I don't have any control over the query string parameters coming in, so I can't change those, but I'd really like to be able to use Spring MVC's data binding abilities, rather than doing it by hand.
How can I do this?
To add some complication to this, some of the parameters will require extensive processing because they map to other objects (such as mapping to a user from just a name) that may not even exist yet and will need to be created. This aspect, I assume, can be handled using property editors. If I run into trouble with this, I will ask another question.
Once I have a partially filled domain object, passing it on to the edit view, etc. is no problem, but I don't know how to properly deal with the initial domain object population.
The only thing I have been able to come up with so far is to have an extra class that has it's properties named to match the inbound query parameters and a function to convert from this intermediary class to my domain class.
This seems like a lot of overhead though just to map between variable names.
Can you not just have the getter named differently from the setter, or have 2 getters and 2 setters if necessary?
private int spn;
// Standard getter/setter
public int getSpn() {
return spn;
}
public void setSpn(int spn) {
this.spn = spn;
}
// More descriptively named getter/setter
public int getShortParameterName() {
return spn;
}
public void setShortParameterName(int spn) {
this.spn = spn;
}
Maybe that is not standard bean convention, but surely would work?

Resources