@@ -40,40 +40,66 @@ public List<AttrAttribute> Get(RelationshipAttribute relationship = null)
4040 return fields ;
4141 }
4242
43+
4344 /// <inheritdoc/>
4445 public virtual void Parse ( KeyValuePair < string , StringValues > queryParameter )
45- {
46- // expected: fields[TYPE ]=prop1,prop2
47- var typeName = queryParameter . Key . Split ( QueryConstants . OPEN_BRACKET , QueryConstants . CLOSE_BRACKET ) [ 1 ] ;
46+ { // expected: articles?fields=prop1,prop2
47+ // articles? fields[articles ]=prop1,prop2
48+ // articles?fields[relationship]=prop1,prop2
4849 var fields = new List < string > { nameof ( Identifiable . Id ) } ;
50+ fields . AddRange ( ( ( string ) queryParameter . Value ) . Split ( QueryConstants . COMMA ) ) ;
4951
50- var relationship = _requestResource . Relationships . SingleOrDefault ( a => a . Is ( typeName ) ) ;
51- if ( relationship == null && string . Equals ( typeName , _requestResource . EntityName , StringComparison . OrdinalIgnoreCase ) == false )
52- throw new JsonApiException ( 400 , $ "fields[{ typeName } ] is invalid") ;
52+ var keySplitted = queryParameter . Key . Split ( QueryConstants . OPEN_BRACKET , QueryConstants . CLOSE_BRACKET ) ;
5353
54- fields . AddRange ( ( ( string ) queryParameter . Value ) . Split ( QueryConstants . COMMA ) ) ;
55- foreach ( var field in fields )
56- {
57- if ( relationship != default )
58- {
59- var relationProperty = _contextEntityProvider . GetContextEntity ( relationship . DependentType ) ;
60- var attr = relationProperty . Attributes . SingleOrDefault ( a => a . Is ( field ) ) ;
61- if ( attr == null )
62- throw new JsonApiException ( 400 , $ "'{ relationship . DependentType . Name } ' does not contain '{ field } '.") ;
54+ if ( keySplitted . Count ( ) == 1 ) // input format: fields=prop1,prop2
55+ foreach ( var field in fields )
56+ RegisterRequestResourceField ( field ) ;
57+ else
58+ { // input format: fields[articles]=prop1,prop2
59+ string navigation = keySplitted [ 1 ] ;
60+ // it is possible that the request resource has a relationship
61+ // that is equal to the resource name, like with self-referering data types (eg directory structures)
62+ // if not, no longer support this type of sparse field selection.
63+ if ( navigation == _requestResource . EntityName && ! _requestResource . Relationships . Any ( a => a . Is ( navigation ) ) )
64+ throw new JsonApiException ( 400 , $ "Use \" ?fields=...\" instead of \" fields[{ navigation } ]\" :" +
65+ $ " the square bracket navigations is now reserved " +
66+ $ "for relationships only. See https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/555#issuecomment-543100865") ;
67+
68+ var relationship = _requestResource . Relationships . SingleOrDefault ( a => a . Is ( navigation ) ) ;
69+ if ( relationship == null )
70+ throw new JsonApiException ( 400 , $ "\" { navigation } \" in \" fields[{ navigation } ]\" is not a valid relationship of { _requestResource . EntityName } ") ;
6371
64- if ( ! _selectedRelationshipFields . TryGetValue ( relationship , out var registeredFields ) )
65- _selectedRelationshipFields . Add ( relationship , registeredFields = new List < AttrAttribute > ( ) ) ;
66- registeredFields . Add ( attr ) ;
67- }
68- else
69- {
70- var attr = _requestResource . Attributes . SingleOrDefault ( a => a . Is ( field ) ) ;
71- if ( attr == null )
72- throw new JsonApiException ( 400 , $ "'{ _requestResource . EntityName } ' does not contain '{ field } '.") ;
72+ foreach ( var field in fields )
73+ RegisterRelatedResourceField ( field , relationship ) ;
7374
74- ( _selectedFields = _selectedFields ?? new List < AttrAttribute > ( ) ) . Add ( attr ) ;
75- }
7675 }
7776 }
77+
78+ /// <summary>
79+ /// Registers field selection queries of the form articles?fields[author]=first-name
80+ /// </summary>
81+ private void RegisterRelatedResourceField ( string field , RelationshipAttribute relationship )
82+ {
83+ var relationProperty = _contextEntityProvider . GetContextEntity ( relationship . DependentType ) ;
84+ var attr = relationProperty . Attributes . SingleOrDefault ( a => a . Is ( field ) ) ;
85+ if ( attr == null )
86+ throw new JsonApiException ( 400 , $ "'{ relationship . DependentType . Name } ' does not contain '{ field } '.") ;
87+
88+ if ( ! _selectedRelationshipFields . TryGetValue ( relationship , out var registeredFields ) )
89+ _selectedRelationshipFields . Add ( relationship , registeredFields = new List < AttrAttribute > ( ) ) ;
90+ registeredFields . Add ( attr ) ;
91+ }
92+
93+ /// <summary>
94+ /// Registers field selection queries of the form articles?fields=title
95+ /// </summary>
96+ private void RegisterRequestResourceField ( string field )
97+ {
98+ var attr = _requestResource . Attributes . SingleOrDefault ( a => a . Is ( field ) ) ;
99+ if ( attr == null )
100+ throw new JsonApiException ( 400 , $ "'{ _requestResource . EntityName } ' does not contain '{ field } '.") ;
101+
102+ ( _selectedFields = _selectedFields ?? new List < AttrAttribute > ( ) ) . Add ( attr ) ;
103+ }
78104 }
79105}
0 commit comments