GraphQl Union input types - graphql

In HotChocolate I have a query type like so
// QueryType.cs
public Task<ContentCategory> FilterContentAsync(string categoryCode, ICollection<Filter> filters, CancellationToken cancellationToken = default)
=> ...;
// Filter.cs
public abstract class Filter
{
public string Type { get;set; }
}
// BooleanFilter.cs
public class BooleanFilter : Filter
{
public bool IsTrue { get; set; }
}
// NumberRangeFilter.cs
public class NumberRangeFilter : Filter
{
public int Min { get; set; }
public int Max { get; set; }
}
when I run the application I get the following error
1. Unable to infer or resolve a schema type from the type reference `Input: Filter`.
Is the following query supported:
filterContent (categoryCode: "All", filters: [{type: "boolean", isTrue: true}, {type: "numberrange", min: 10, max: 60}]) {
id
}

Seems that this is not implemented currently.
Here is an issue in hotchocolate repository. Currently (Jul 2021) it is open and have "backlog" label, so I can assume that input unions are not implemented yet.
And here is a tweet of one of developers of hotChocolate, where he says
We are implementing the #graphql oneof spec proposal for Hot Chocolate
12... let the input unions come :)
By the way there is another link to discussion about possible implementations for input union problem. So according to this, there is 7 various ideas how to change the spec, 1 winner (the 7th option) and no one single link to possible implementations.

Related

Web API method with FromUri attribute is not working in Postman

I have written the below simple Web API method.
[HttpGet]
[HttpPost]
public int SumNumbers([FromUri]Numbers calc, [FromUri]Operation op)
{
int result = op.Add ? calc.First + calc.Second : calc.First - calc.Second;
return op.Double ? result * 2 : result;
}
Below is the model class for Numbers:
public class Numbers
{
public int First { get; set; }
public int Second { get; set; }
}
Below is the model class for Operation:
public class Operation
{
public bool Add { get; set; }
public bool Double { get; set; }
}
Below is how I am trying to test in Postman. But, as you can see I am getting "0" as output. When debugged the code, understood that values are not passing from Postman into code.
One another user also posted the same problem here. But, whatever the resolution he showed, I am doing already, but I am not getting answer.
Can anyone please suggest where I am doing wrong?
There are 2 major issues with your post, firstly your controller (due to [FromUri]
binding) is specifying that the arguments need to be passed as Query String parameters and not Http Header values.
The second issue is that you have defined two complex type parameters that you want to obtain the values form the URI, this is not supported.
How to pass in Uri complex objects without using custom ModelBinders or any serialization?
This is a great writeup on how to fully exploit the [FromUriAttribute][2] up to ASP.Net Core 2.2, many of the principals apply to the FromQueryAttribute which is still used the current in ASP.Net 6.
We can use [FromUri] to bind multiple primitive typed parameters, or we can bind 1 single complex typed parameter. You cannot combine the two concepts, the reason for this is that when a complex type is used ALL of the query string arguments are bound to that single complex type.
So your options are to create a new complex type that combines all the properties from both types, or declare all the properties of both types as primitive parameters to the method:
http://localhost:29844/api/bindings/SumNumbers1?First=3&Second=2&Add=True&Double=False
http://localhost:29844/api/bindings/SumNumbers2?First=3&Second=2&Add=True&Double=False
[HttpGet]
[HttpPost]
public int SumNumbers1([FromUri] int First, [FromUri] int Second, [FromUri] bool Add, [FromUri] bool Double)
{
int result = Add ? First + Second : First - Second;
return Double ? result * 2 : result;
}
[HttpGet]
[HttpPost]
public int SumNumbers2([FromUri] SumRequest req)
{
int result = req.Add ? req.First + req.Second : req.First - req.Second;
return req.Double ? result * 2 : result;
}
public class SumRequest
{
public int First { get; set; }
public int Second { get; set; }
public bool Add { get; set; }
public bool Double { get; set; }
}
It is also technically possible to use a nested structure, where you wrap the multiple complex with a single outer complex type. Depending on your implementation and host constraints you may need additional configuration to support using . in the query parameters, but a nested or wrapped request implementation would look like this:
http://localhost:29844/api/bindings/SumNumbers3?Calc.First=3&Calc.Second=2&Op.Add=True&Op.Double=False
[HttpGet]
[HttpPost]
public int SumNumbers3([FromUri] WrappedRequest req)
{
int result = req.Op.Add ? req.Calc.First + req.Calc.Second : req.Calc.First - req.Calc.Second;
return req.Op.Double ? result * 2 : result;
}
public class WrappedRequest
{
public Numbers Calc { get; set; }
public Operation Op { get; set; }
}
It is also possible to use a combination of Http Headers and query string parameters, however these are generally harder (less common) to manage from a client perspective.
It is more common with complex parameter scenarios (not to mention more REST compliant) to force the caller to use POST to access your calculation endpoint, then multiple complex types are simpler to support from both a client and API perspective.
If you want to receive parameters using FromUri, shouldn't you pass them in the URL when doing the GET call? A simpler call would be something like this:
[HttpGet]
[Route("{first:int}/{second:int}")]
public int SumNumbers([FromUri]int first, [FromUri]int second)
{
return first+second;
}
And in Postman your call should be more like this (the url)
http://localhost:29844/api/bindings/SumNumbers/5/7
and this would return 12!
Now if you want to pass First and Second as headers and not in the url then you don't want to use FromUri and then your code would change a little bit (you will then need to read the request and dissect it to get every header alone. Something like this:
HttpRequestMessage request = Request ?? new HttpRequestMessage();
string first = request.Headers.GetValues("First").FirstOrDefault();
string second = request.Headers.GetValues("Second").FirstOrDefault();

How to query and return all documents in documentdb using linq

let problemDocument = documentClient.CreateDocumentQuery<ProblemDatabaseModel>("")
problemDocument
doesn't seem to work
(problemDocument.Select(fun problem -> problem))
doesn't seem to work
(problemDocument.Where(fun problem -> problem.id = problem.id))
doesn't seem to work either. Any ideas?
If you want to query all document in document db, please try to below code:
documentClient.CreateDocumentQuery<ProblemDatabaseModel>("").ToList();
Please note that, we can store different json entity in documentDB, if document property does not in your data model, it will give a default value. I have a simple test for this:
Data model:
public class Cred
{
[JsonProperty(PropertyName = "id")]
public string ID { get; set; }
[JsonProperty(PropertyName = "title")]
public string Title { get; set; }
[JsonProperty(PropertyName = "credits")]
public int Credits { get; set; }
[JsonProperty(PropertyName = "authordetails")]
public AuthDetail AuthInfo { get; set; }
}
If json data in documentDB is:
{
"id": "CDC103",
"title": "Fundamentals of database design",
"authordetails": {
"Name": "dave",
"Age": 33
},
"custom":"test"
}
client.CreateDocumentQuery<Cred>(UriFactory.CreateDocumentCollectionUri("jambordb", "jamborcols")).ToList();
Here is the result:
From the screenshot we know that, the property "custom" will not included in our data model. and the credits will give a default value 0.

Combining Linq Expressions for Dto Selector

We have a lot of Dto classes in our project and on various occasions SELECT them using Expressions from the entity framework context. This has the benefit, that EF can parse our request, and build a nice SQL statement out of it.
Unfortunatly, this has led to very big Expressions, because we have no way of combining them.
So if you have a class DtoA with 3 properties, and one of them is of class DtoB with 5 properties, and again one of those is of class DtoC with 10 properties, you would have to write one big selector.
public static Expression<Func<ClassA, DtoA>> ToDto =
from => new DtoA
{
Id = from.Id,
Name = from.Name,
Size = from.Size,
MyB = new DtoB
{
Id = from.MyB.Id,
...
MyCList = from.MyCList.Select(myC => new DtoC
{
Id = myC.Id,
...
}
}
};
Also, they cannot be reused. When you have DtoD, which also has a propertiy of class DtoB, you would have to paste in the desired code of DtoB and DtoC again.
public static Expression<Func<ClassD, DtoD>> ToDto =
from => new DtoD
{
Id = from.Id,
Length = from.Length,
MyB = new DtoB
{
Id = from.MyB.Id,
...
MyCList = from.MyCList.Select(myC => new DtoC
{
Id = myC.Id,
...
}
}
};
So this will escalate pretty fast. Please note that the mentioned code is just an example, but you get the idea.
I would like to define an expression for each class and then combine them as required, as well as EF still be able to parse it and generate the SQL statement so to not lose the performance improvement.
How can i achieve this?
Have you thought about using Automapper ? You can define your Dtos and create a mapping between the original entity and the Dto and/or vice versa, and using the projection, you don't need any select statements as Automapper will do it for you automatically and it will project only the dto's properties into SQL query.
for example, if you have a Person table with the following structure:
public class Person
{
public int Id { get; set; }
public string Title { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
public string Initial { get; set; }
public string PreferredName { get; set; }
public string FormerTitle { get; set; }
public string FormerFamilyName { get; set; }
public string FormerGivenName { get; set; }
}
and your dto was like this :
public class PersonDto
{
public int Id { get; set; }
public string Title { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
}
You can create a mapping between Person and PersonDto like this
Mapper.CreateMap<Person, PersonDto>()
and when you query the database using Entity Framework (for example), you can use something like this to get PersonDto columns only:
ctx.People.Where(p=> p.FamilyName.Contains("John"))
.Project()
.To<PersonDto>()
.ToList();
which will return a list of PersonDtos that has a family name contains "John", and if you run a sql profiler for example you will see that only the PersonDto columns were selected.
Automapper also supports hierachy, if your Person for example has an Address linked to it that you want to return AddressDto for it.
I think it worth to have a look and check it, it cleans a lot of the mess that manual mapping requires.
I thought about it a little, and I didn't come up with any "awesome" solution.
Essentially you have two general choices here,
Use placeholder and rewrite expression tree entirely.
Something like this,
public static Expression<Func<ClassA, DtoA>> DtoExpression{
get{
Expression<Func<ClassA, DtoA>> dtoExpression = classA => new DtoA(){
BDto = Magic.Swap(ClassB.DtoExpression),
};
// todo; here you have access to dtoExpression,
// you need to use expression transformers
// in order to find & replace the Magic.Swap(..) call with the
// actual Expression code(NewExpression),
// Rewriting the expression tree is no easy task,
// but EF will be able to understand it this way.
// the code will be quite tricky, but can be solved
// within ~50-100 lines of code, I expect.
// For that, see ExpressionVisitor.
// As ExpressionVisitor detects the usage of Magic.Swap,
// it has to check the actual expression(ClassB.DtoExpression),
// and rebuild it as MemberInitExpression & NewExpression,
// and the bindings have to be mapped to correct places.
return Magic.Rebuild(dtoExpression);
}
The other way is to start using only Expression class(ditching the LINQ). This way you can write the queries from zero, and reusability will be nice, however, things get harder & you lose type safety. Microsoft has nice reference about dynamic expressions. If you structure everything that way, you can reuse a lot of the functionality. Eg, you define NewExpression and then you can later reuse it, if needed.
The third way is to basically use lambda syntax: .Where, .Select etc.. This gives you definitely better "reusability" rate. It doesn't solve your problem 100%, but it can help you to compose queries a bit better. For example: from.MyCList.Select(dtoCSelector)

How can I use nested types with NEST client for Elastic Search

I ran in to some issues whilst trying to use statistical facets on my documents in Elastic Search. This resulted in the following posts on the Elastic Search google group - see https://groups.google.com/forum/#!topic/elasticsearch/wNjrnAC_KOY. I tried to apply the recommendation in the answer about using Nested types with in the document to provide distinct sums on the collections property(see https://groups.google.com/forum/#!topic/elasticsearch/wNjrnAC_KOY)
That is I would have many instances of MyType with a collection of MyItem. Some collections of MyItem will have instances with matching amounts i.e. the first document could have two instances of myitem, both with an amount of 100. Without nested types I don't believe statistical facets will aggregate each amount as they're not unique.
So I've created a document structure (similar to below) and populated my index. Before populating my index I've used the following code in an effort to created a nested document.
client.MapFromAttributes<Page>();
[ElasticType(Name="page", DateDetection = true, NumericDetection = true, SearchAnalyzer = "standard",IndexAnalyzer = "standard")]
public class MyType
{
public int TypeId { get; set; }
public string Name { get; set; }
public ANotherType AnotherProperty { get; set; }
public DateTime Created { get; set; }
[ElasticProperty(Type = FieldType.nested, Name="mycollection")]
public List<MyItem> MyItems { get;
}
public class MyItem
{
public decimal Amount {get;set;}
}
However, when I run the following query via the nest api I don't get any results.
query.Index("pages")
.Type("page")
.From(0)
.Size(100)
.FacetStatistical("TotalAmount", x => x.Nested("donations")
.OnField("amount")));
More over I've also tried the following via the Chrome plugin PostMan :
{
"facets": {
"test": {
"statistical": {
"field": "amount"
},
"nested": "mycollection"
}
},
"size":0
}'
and get a response that notes :
"..facet nested path [mycollection] is not nested.."
Any thoughts on this would be great.
Tim
Try to map you object as followed:
client.MapFluent<MyType>(m=>m
.MapFromAttributes()
.NestedObject<MyItem>(no=>no
.Name(p=>p.MyItems.First())
.Dynamic()
.Enabled()
.IncludeInAll()
.IncludeInParent()
.IncludeInRoot()
.MapFromAttributes()
.Path("full")
.Properties(pprops => pprops
.String(ps => ps
.Name(p => p.FirstName)
.Index(FieldIndexOption.not_analyzed)
)
//etcetera
)
)
);
The client.MapFromAttributes() is very limited and will probably be removed in the 1.0 release. Its great to annotate property names but quickly becomes limitted in what it can express. The MapFromAttributes() in the mapfluent call is still a great way to type int's as int, float's as floats, DateTime's as dates etcetera.

Do i need to create automapper createmap both ways?

This might be a stupid question! (n00b to AutoMapper and time-short!)
I want to use AutoMapper to map from EF4 entities to ViewModel classes.
1) If I call
CreateMap<ModelClass, ViewModelClass>()
then do I also need to call
CreateMap<ViewModelClass, ModelClass>()
to perform the reverse?
2) If two classes have the same property names, then do I need a CreateMap statement at all, or is this just for "specific/custom" mappings?
For the info of the people who stumble upon this question. There appears to be now a built-in way to achieve a reverse mapping by adding a .ReverseMap() call at the end of your CreateMap() configuration chain.
In AutoMapper you have a Source type and a Destination type. So you will be able to map between this Source type and Destination type only if you have a corresponding CreateMap. So to answer your questions:
You don't need to define the reverse mapping. You have to do it only if you intend to map back.
Yes, you need to call CreateMap to indicate that those types are mappable otherwise an exception will be thrown when you call Map<TSource, TDest> telling you that a mapping doesn't exist between the source and destination type.
I've used an extension method do mapping both ways
public static IMappingExpression<TDestination, TSource> BothWays<TSource, TDestination>
(this IMappingExpression<TSource, TDestination> mappingExpression)
{
return Mapper.CreateMap<TDestination, TSource>();
}
usage:
CreateMap<Source, Dest>().BothWays();
Yes, or you can call CreateMap<ModelClass, ViewModelClass>().ReverseMap().
If two classes have same Member(Property,Field,GetMethod()), you needn't call CreateMap<TSrc,TDest>. Actually, if every member in TDest are all exist in TSrc, you needn't call CreateMap<TSrc,TDest>. The following code works.
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
class Person2
{
public string Name { get; set; }
public int? Age { get; set; }
public DateTime BirthTime { get; set; }
}
public class NormalProfile : Profile
{
public NormalProfile()
{
//CreateMap<Person2, Person>();//
}
}
var cfg = new MapperConfiguration(c =>
{
c.AddProfile<NormalProfile>();
});
//cfg.AssertConfigurationIsValid();
var mapper = cfg.CreateMapper();
var s3 = mapper.Map<Person>(new Person2 { Name = "Person2" });

Resources