I'm adding Hot Chocolate(GraphQL) to an existing ASP.Net Core project with a Web API and reusing the models that are used by the Web API. One of the models has an IDictionary<string, object> property that is serialized into a dynamic JSON with Web API.
The Model
public class Theme
{
...
public IDictionary<string, object> Styles { get; set; }
...
}
that with the Web API can be serialized to
{
...
styles: {
header: {
color: "#fff",
background: "rgba(255, 255, 255, 0)",
boxShadow: "", position: "fixed"},
...
},
borderRadius: "4px",
...
}
...
}
With Hot Chocolate, I'm reusing the model and adds GraphQL in startup with
services.AddGraphQL(sp => SchemaBuilder.New()
.AddServices(sp)
.AddQueryType(d => d.Name("Query"))
...
.AddType<Theme>()
.Create());
The schema that is generated becomes
type Theme {
...
styles: [KeyValuePairOfStringAndObject!]
...
}
and only key can be retrieved
{
themes(...) {
edges {
node {
name
styles{
key
}
}
}
}
}
with the following response
{
"themes": {
"edges": [
{
"node": {
...
"styles": [
{
"key": "header"
},
{
"key": "borderRadius"
},
...
]
}
}
]
}
}
I would like to set up Hot Chocolate to make it possible to write a GraphQL query that gives the same dynamic result as the Web API.
UPDATE
The source is a JSON string that is deserialized to a Dictionary<string, object> with
var jsonString = "{\"header\":{\"color\":\"#fff\"},\"borderRadius\":\"4px\"}";
theme.Styles = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
The problem is that the resulting dictionary isn't recursively serialized to a Dictionary<string, object>.
Hot Chocolate has an AnyType for dynamic data structures. But the AnyType by default is not implicitly inferred from types.
You basically have two options here. Either declare the type on your type with an attribute (or do the same with the fluent API).
Pure Code-First:
public class Theme
{
...
[GraphQLType(typeof(AnyType))]
public IDictionary<string, object> Styles { get; set; }
...
}
Code-First with Schema Types:
public class ThemeType : ObjectType<Theme>
{
protected override void Configure(IObjectTypeDescriptor<Theme> descriptor)
{
descriptor.Field(t => t.Styles).Type<AnyType>();
}
}
Alternatively, you can say that in your schema all IDictionary<string, object>
are any types in which case you do not need to explicitly define the type:
services.AddGraphQL(sp => SchemaBuilder.New()
.AddServices(sp)
.AddQueryType(d => d.Name("Query"))
...
.AddType<Theme>()
.BindClrType<IDictionary<string, object>, AnyType>()
.Create());
I hope this helps.