@@ -40,40 +40,66 @@ public List<AttrAttribute> Get(RelationshipAttribute relationship = null)
40
40
return fields ;
41
41
}
42
42
43
+
43
44
/// <inheritdoc/>
44
45
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
48
49
var fields = new List < string > { nameof ( Identifiable . Id ) } ;
50
+ fields . AddRange ( ( ( string ) queryParameter . Value ) . Split ( QueryConstants . COMMA ) ) ;
49
51
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 ) ;
53
53
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 } ") ;
63
71
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 ) ;
73
74
74
- ( _selectedFields = _selectedFields ?? new List < AttrAttribute > ( ) ) . Add ( attr ) ;
75
- }
76
75
}
77
76
}
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
+ }
78
104
}
79
105
}
0 commit comments