Closed patcharees closed 2 months ago
This can be done using a resource definition. See https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb/pull/54 for an example. The second commit backports to the version you're using.
I’m newbie. I have a lot of fields to exclude/include. Is there a better way to implement this than looping one by one?
public override SparseFieldSetExpression? OnApplySparseFieldSet(SparseFieldSetExpression? existingSparseFieldSet)
{
if (!_queryStringAccessor.Query.ContainsKey("fields[books]"))
{
return existingSparseFieldSet
.Excluding<Book>(book => book.Refs1, ResourceGraph)
.Excluding<Book>(book => book.Refs2, ResourceGraph)
.Excluding<Book>(book => book.Refs3, ResourceGraph);
}
return existingSparseFieldSet;
}
There's no looping in the code. You can ensure fields are always returned using the .Including
method, which works similarly.
More importantly, JSON:API is loved by clients because it allows them to specify exactly what data to fetch and return. A server that is sending fields the client never asked for negates that optimized network bandwidth experience (between client and server, as well as between server and database). A better approach would be to break down your data structure into smaller parts, so you won't need to include/exclude so many fields.
I got it. Thanks :)
I created the following method to 1) return all DefaultAttributes (primitive & string) 2) return all DefaultAttributes + specific fields by fields[]
The first case works well. But the 2nd returns only the specific fields, even though I add more attributes into existingSparseFieldSet. Do you know why?
public override SparseFieldSetExpression? OnApplySparseFieldSet(SparseFieldSetExpression? existingSparseFieldSet)
{
//var resourceContext = ResourceGraph.GetResourceContext<TResource>();
// set default attribute first
var attributes = _resourceGraph.GetResourceContext<TResource>().Attributes;
var fields = "fields[" + _resourceGraph.GetResourceContext<TResource>().PublicName + "]";
var defaultAttributes = (IReadOnlyCollection<ResourceFieldAttribute>)
attributes.Where(a => PageConfigurableDefinition<TResource>.IsDefaultAttribute(a)).ToList();
if (_queryStringAccessor.Query.ContainsKey(fields) && existingSparseFieldSet != null)
{
HashSet<ResourceFieldAttribute> fieldSet = existingSparseFieldSet.Fields.ToHashSet();
foreach (var attr in defaultAttributes)
fieldSet.Add(attr);
return new SparseFieldSetExpression(fieldSet);
}
else
{
return new SparseFieldSetExpression(defaultAttributes);
}
}
This does not work
public override SparseFieldSetExpression? OnApplySparseFieldSet(SparseFieldSetExpression? existingSparseFieldSet)
{
return existingSparseFieldSet
.Including<Book>(t => t.bookId, ResourceGraph)
.Including<Book>(t => t.bookGroup, ResourceGraph)
.Including<Book>(t => t.bookGroupName, ResourceGraph);
}
You're right, using .Including()
doesn't add extra fields to the JSON response. I assumed it would, but that's not the case. It is actually by design and documented at https://www.jsonapi.net/api/JsonApiDotNetCore.Resources.IResourceDefinition-2.html#JsonApiDotNetCore_Resources_IResourceDefinition_2_OnApplySparseFieldSet_JsonApiDotNetCore_Queries_Expressions_SparseFieldSetExpression__remarks:
Including extra fields from this method will retrieve them, but not include them in the json output. This enables you to expose calculated properties whose value depends on a field that is not in the sparse fieldset.
So in that case, what you want is not possible. You'll just need to send the desired fields in the query string.
SUMMARY
If it is possible to make some attributes unavailable by default and vice versa if specify explicitly in the request?
DETAILS
I am working with a data collection in mongodb that is complex and contains many nested data structure (inside its own collection). I wonder if it is possible to define some [attr ?] attribute that make view of nested data structure unavailable by default, and vice versa if specify explicitly in the request somehow?
STEPS TO REPRODUCE
VERSIONS USED