Skip to content

Commit 533623d

Browse files
committed
Consolidate JSON API field allowlist
1 parent 2124e3e commit 533623d

10 files changed

Lines changed: 38 additions & 144 deletions

File tree

.formatter.exs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ spark_locals_without_parens = [
7777
router: 1,
7878
serve_schema?: 1,
7979
show_fields: 1,
80-
show_relationships: 1,
8180
show_raised_errors?: 1,
8281
tag: 1,
8382
type: 1,

documentation/dsls/DSL-AshJsonApi.Resource.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ end
6868
| [`include_nil_values?`](#json_api-include_nil_values?){: #json_api-include_nil_values? } | `any` | | Whether or not to include properties for values that are nil in the JSON output |
6969
| [`default_fields`](#json_api-default_fields){: #json_api-default_fields } | `list(atom)` | | The fields to include in the object if the `fields` query parameter does not specify. Defaults to all public |
7070
| [`hide_fields`](#json_api-hide_fields){: #json_api-hide_fields } | `list(atom)` | `[]` | A list of fields to hide from the generated OpenAPI specification. Applies to attributes, relationships, calculations, and aggregates. |
71-
| [`show_fields`](#json_api-show_fields){: #json_api-show_fields } | `list(atom)` | | A list of attributes, calculations, and aggregates to show in the JSON:API response and generated OpenAPI specification. If not specified, all public non-relationship fields are allowed in responses, and all public non-relationship fields except those in `hide_fields` are shown in the generated OpenAPI specification. |
72-
| [`show_relationships`](#json_api-show_relationships){: #json_api-show_relationships } | `list(atom)` | | A list of relationships to show in the JSON:API response and generated OpenAPI specification. If not specified, all public relationships are allowed in responses, and all public relationships except those in `hide_fields` are shown in the generated OpenAPI specification. |
71+
| [`show_fields`](#json_api-show_fields){: #json_api-show_fields } | `list(atom)` | | A list of fields to show in the JSON:API response and generated OpenAPI specification. Applies to attributes, relationships, calculations, and aggregates. If not specified, all public fields are allowed in responses, and all public fields except those in `hide_fields` are shown in the generated OpenAPI specification. |
7372
| [`derive_sort?`](#json_api-derive_sort?){: #json_api-derive_sort? } | `boolean` | `true` | Whether or not to derive a sort parameter based on the sortable fields of the resource |
7473
| [`derive_filter?`](#json_api-derive_filter?){: #json_api-derive_filter? } | `boolean` | `true` | Whether or not to derive a filter parameter based on the sortable fields of the resource |
7574
| [`relationship_meta_in`](#json_api-relationship_meta_in){: #json_api-relationship_meta_in } | `keyword` | `[]` | Configures how incoming JSON:API `meta` keys on relationship resource identifiers map to join resource attributes for many_to_many relationship writes. Use together with `relationship_meta_out` for reads. Each relationship you want to support must declare both mappings explicitly. |

lib/ash_json_api/includes/parser.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,23 @@ defmodule AshJsonApi.Includes.Parser do
3737
list
3838
|> Enum.flat_map(fn
3939
{key, value} when is_list(value) ->
40-
if AshJsonApi.Resource.Info.allow_relationship?(resource, key) do
40+
if AshJsonApi.Resource.Info.allow_field?(resource, key) do
4141
relationship = Ash.Resource.Info.public_relationship(resource, key)
4242
[{to_string(key), to_nested_map(value, relationship.destination)}]
4343
else
4444
[]
4545
end
4646

4747
{key, value} when is_atom(value) ->
48-
if AshJsonApi.Resource.Info.allow_relationship?(resource, key) do
48+
if AshJsonApi.Resource.Info.allow_field?(resource, key) do
4949
relationship = Ash.Resource.Info.public_relationship(resource, key)
5050
[{to_string(key), to_nested_map([value], relationship.destination)}]
5151
else
5252
[]
5353
end
5454

5555
value ->
56-
if AshJsonApi.Resource.Info.allow_relationship?(resource, value) do
56+
if AshJsonApi.Resource.Info.allow_field?(resource, value) do
5757
relationship = Ash.Resource.Info.public_relationship(resource, value)
5858
[{to_string(value), to_nested_map(value, relationship.destination)}]
5959
else

lib/ash_json_api/json_schema/open_api.ex

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ if Code.ensure_loaded?(OpenApiSpex) do
217217
|> Enum.flat_map(fn resource ->
218218
resource
219219
|> Ash.Resource.Info.public_relationships()
220-
|> filter_shown_relationships(resource)
220+
|> filter_shown_fields(resource)
221221
end)
222222
|> Enum.map(& &1.destination)
223223
|> Enum.reject(&(&1 in resources))
@@ -245,7 +245,7 @@ if Code.ensure_loaded?(OpenApiSpex) do
245245
|> Stream.flat_map(fn resource ->
246246
resource
247247
|> Ash.Resource.Info.relationships()
248-
|> filter_shown_relationships(resource)
248+
|> filter_shown_fields(resource)
249249
end)
250250
|> Stream.filter(& &1.public?)
251251
|> Enum.any?(&(&1.destination == resource))
@@ -277,18 +277,6 @@ if Code.ensure_loaded?(OpenApiSpex) do
277277
Enum.filter(fields, &show_field?(resource, &1))
278278
end
279279

280-
defp show_relationship?(resource, %{name: name}) do
281-
AshJsonApi.Resource.Info.show_relationship?(resource, name)
282-
end
283-
284-
defp show_relationship?(resource, relationship) do
285-
AshJsonApi.Resource.Info.show_relationship?(resource, relationship)
286-
end
287-
288-
defp filter_shown_relationships(relationships, resource) do
289-
Enum.filter(relationships, &show_relationship?(resource, &1))
290-
end
291-
292280
defp resource_filter_schemas(domains, resource, acc) do
293281
{field_types, acc} = filter_field_types(resource, acc)
294282

@@ -1384,7 +1372,7 @@ if Code.ensure_loaded?(OpenApiSpex) do
13841372
defp resource_relationships(resource) do
13851373
resource
13861374
|> Ash.Resource.Info.public_relationships()
1387-
|> filter_shown_relationships(resource)
1375+
|> filter_shown_fields(resource)
13881376
|> Enum.filter(fn %{destination: destination} ->
13891377
AshJsonApi.Resource.Info.type(destination)
13901378
end)
@@ -2141,7 +2129,7 @@ if Code.ensure_loaded?(OpenApiSpex) do
21412129
is_nil(relationship) ->
21422130
{:halt, false}
21432131

2144-
!show_relationship?(current_resource, relationship_name) ->
2132+
!show_field?(current_resource, relationship_name) ->
21452133
{:halt, false}
21462134

21472135
true ->
@@ -2576,7 +2564,7 @@ if Code.ensure_loaded?(OpenApiSpex) do
25762564
defp required_relationship_attributes(resource, relationship_arguments, action) do
25772565
action.arguments
25782566
|> Enum.filter(&has_relationship_argument?(relationship_arguments, &1.name))
2579-
|> Enum.filter(&show_relationship?(resource, &1.name))
2567+
|> Enum.filter(&show_field?(resource, &1.name))
25802568
|> Enum.reject(& &1.allow_nil?)
25812569
|> Enum.map(fn arg ->
25822570
AshJsonApi.Resource.Info.argument_to_json_key(resource, action.name, arg.name)
@@ -2588,7 +2576,7 @@ if Code.ensure_loaded?(OpenApiSpex) do
25882576
defp write_relationships(resource, relationship_arguments, action) do
25892577
action.arguments
25902578
|> Enum.filter(&has_relationship_argument?(relationship_arguments, &1.name))
2591-
|> Enum.filter(&show_relationship?(resource, &1.name))
2579+
|> Enum.filter(&show_field?(resource, &1.name))
25922580
|> Map.new(fn argument ->
25932581
data = resource_write_relationship_field_data(resource, argument)
25942582

@@ -2833,7 +2821,7 @@ if Code.ensure_loaded?(OpenApiSpex) do
28332821
do: relationship_destination(resource, include) |> List.wrap()
28342822

28352823
defp relationship_destination(resource, include) do
2836-
if show_relationship?(resource, include) do
2824+
if show_field?(resource, include) do
28372825
resource
28382826
|> Ash.Resource.Info.public_relationship(include)
28392827
|> case do
@@ -3080,7 +3068,7 @@ if Code.ensure_loaded?(OpenApiSpex) do
30803068

30813069
resource
30823070
|> Ash.Resource.Info.public_relationships()
3083-
|> filter_shown_relationships(resource)
3071+
|> filter_shown_fields(resource)
30843072
|> Enum.filter(
30853073
&(&1.destination in all_resources &&
30863074
AshJsonApi.Resource.Info.derive_filter?(&1.destination) &&

lib/ash_json_api/request.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ defmodule AshJsonApi.Request do
696696
defp public_related(resource, [path | rest]) do
697697
case public_relationship(resource, path) do
698698
%{destination: destination, name: name} ->
699-
if AshJsonApi.Resource.Info.allow_relationship?(resource, name) do
699+
if AshJsonApi.Resource.Info.allow_field?(resource, name) do
700700
public_related(destination, rest)
701701
end
702702

@@ -817,7 +817,7 @@ defmodule AshJsonApi.Request do
817817
end
818818

819819
rel = public_relationship(resource, key) ->
820-
if AshJsonApi.Resource.Info.allow_relationship?(resource, rel.name) do
820+
if AshJsonApi.Resource.Info.allow_field?(resource, rel.name) do
821821
fields = Map.update(request.fields, resource, [rel.name], &[rel.name | &1])
822822
%{request | fields: fields}
823823
else
@@ -1059,7 +1059,7 @@ defmodule AshJsonApi.Request do
10591059
Keyword.has_key?(includes, key) ->
10601060
includes
10611061

1062-
AshJsonApi.Resource.Info.allow_relationship?(resource, key) ->
1062+
AshJsonApi.Resource.Info.allow_field?(resource, key) ->
10631063
Keyword.put(includes, key, :linkage_only)
10641064

10651065
true ->

lib/ash_json_api/resource/info.ex

Lines changed: 11 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,12 @@ defmodule AshJsonApi.Resource.Info do
7575
Extension.get_opt(resource, [:json_api], :hide_fields, [], true)
7676
end
7777

78-
@doc "Non-relationship fields to show in JSON:API responses and the generated API specification"
78+
@doc "Fields to show in JSON:API responses and the generated API specification"
7979
def show_fields(resource) do
8080
Extension.get_opt(resource, [:json_api], :show_fields, nil, true)
8181
end
8282

83-
@doc "Relationships to show in JSON:API responses and the generated API specification"
84-
def show_relationships(resource) do
85-
Extension.get_opt(resource, [:json_api], :show_relationships, nil, true)
86-
end
87-
88-
@doc "Whether or not a given non-relationship field should be shown in the generated API specification"
83+
@doc "Whether or not a given field should be shown in the generated API specification"
8984
def show_field?(resource, %{name: name}) do
9085
show_field?(resource, name)
9186
end
@@ -95,9 +90,6 @@ defmodule AshJsonApi.Resource.Info do
9590
field in hide_fields(resource) ->
9691
false
9792

98-
Ash.Resource.Info.public_relationship(resource, field) ->
99-
false
100-
10193
is_nil(show_fields(resource)) ->
10294
true
10395

@@ -106,69 +98,33 @@ defmodule AshJsonApi.Resource.Info do
10698
end
10799
end
108100

109-
@doc "Whether or not a given relationship should be shown in the generated API specification"
110-
def show_relationship?(resource, %{name: name}) do
111-
show_relationship?(resource, name)
112-
end
113-
114-
def show_relationship?(resource, relationship) do
115-
cond do
116-
relationship in hide_fields(resource) ->
117-
false
118-
119-
is_nil(show_relationships(resource)) ->
120-
true
121-
122-
true ->
123-
relationship in show_relationships(resource)
124-
end
125-
end
126-
127101
@doc "Whether or not a route should be shown in the generated API specification"
128102
def show_route?(_resource, %{relationship: nil}), do: true
129103

130104
def show_route?(resource, %{relationship: relationship}) do
131-
show_relationship?(resource, relationship)
105+
show_field?(resource, relationship)
132106
end
133107

134-
@doc "Whether or not a given non-relationship field is allowed in the JSON:API response"
108+
@doc "Whether or not a given field is allowed in the JSON:API response"
135109
def allow_field?(resource, %{name: name}) do
136110
allow_field?(resource, name)
137111
end
138112

139113
def allow_field?(resource, field) do
140-
cond do
141-
Ash.Resource.Info.public_relationship(resource, field) ->
142-
false
143-
144-
is_nil(show_fields(resource)) ->
145-
true
146-
147-
true ->
148-
field in show_fields(resource)
149-
end
150-
end
151-
152-
@doc "Whether or not a given relationship is allowed in the JSON:API response"
153-
def allow_relationship?(resource, %{name: name}) do
154-
allow_relationship?(resource, name)
155-
end
156-
157-
def allow_relationship?(resource, relationship) do
158-
case show_relationships(resource) do
114+
case show_fields(resource) do
159115
nil -> true
160-
show_relationships -> relationship in show_relationships
116+
show_fields -> field in show_fields
161117
end
162118
end
163119

164120
@doc "Whether or not a route is allowed in the runtime JSON:API router"
165121
def allow_route?(_resource, %{relationship: nil}), do: true
166122

167123
def allow_route?(resource, %{relationship: relationship}) do
168-
allow_relationship?(resource, relationship)
124+
allow_field?(resource, relationship)
169125
end
170126

171-
@doc "Filters non-relationship fields to those that should be shown in the generated API specification"
127+
@doc "Filters fields to those that should be shown in the generated API specification"
172128
def filter_shown_fields(fields, resource) when is_list(fields) and is_atom(resource) do
173129
filter_shown_fields(resource, fields)
174130
end
@@ -177,29 +133,13 @@ defmodule AshJsonApi.Resource.Info do
177133
Enum.filter(fields, &show_field?(resource, &1))
178134
end
179135

180-
@doc "Filters relationships to those that should be shown in the generated API specification"
181-
def filter_shown_relationships(relationships, resource)
182-
when is_list(relationships) and is_atom(resource) do
183-
filter_shown_relationships(resource, relationships)
184-
end
185-
186-
def filter_shown_relationships(resource, relationships) do
187-
Enum.filter(relationships, &show_relationship?(resource, &1))
188-
end
189-
190136
@doc "Filters a sparse fieldset or default field list to fields and relationships shown in the generated API specification"
191137
def filter_shown_fieldset(fields, resource) when is_list(fields) and is_atom(resource) do
192138
filter_shown_fieldset(resource, fields)
193139
end
194140

195141
def filter_shown_fieldset(resource, fields) do
196-
Enum.filter(fields, fn field ->
197-
if Ash.Resource.Info.public_relationship(resource, field) do
198-
show_relationship?(resource, field)
199-
else
200-
show_field?(resource, field)
201-
end
202-
end)
142+
Enum.filter(fields, &show_field?(resource, &1))
203143
end
204144

205145
@doc "Filters a sparse fieldset or default field list to fields and relationships allowed in responses"
@@ -208,26 +148,10 @@ defmodule AshJsonApi.Resource.Info do
208148
end
209149

210150
def filter_allowed_fieldset(resource, fields) do
211-
Enum.filter(fields, fn field ->
212-
if Ash.Resource.Info.public_relationship(resource, field) do
213-
allow_relationship?(resource, field)
214-
else
215-
allow_field?(resource, field)
216-
end
217-
end)
218-
end
219-
220-
@doc "Filters relationships to those that are allowed in responses"
221-
def filter_allowed_relationships(relationships, resource)
222-
when is_list(relationships) and is_atom(resource) do
223-
filter_allowed_relationships(resource, relationships)
224-
end
225-
226-
def filter_allowed_relationships(resource, relationships) do
227-
Enum.filter(relationships, &allow_relationship?(resource, &1))
151+
Enum.filter(fields, &allow_field?(resource, &1))
228152
end
229153

230-
@doc "Default response fields filtered by `show_fields` and `show_relationships`"
154+
@doc "Default response fields filtered by `show_fields`"
231155
def default_response_fields(resource) do
232156
resource
233157
|> default_fields()

lib/ash_json_api/resource/resource.ex

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -566,12 +566,7 @@ defmodule AshJsonApi.Resource do
566566
show_fields: [
567567
type: {:list, :atom},
568568
doc:
569-
"A list of attributes, calculations, and aggregates to show in the JSON:API response and generated OpenAPI specification. If not specified, all public non-relationship fields are allowed in responses, and all public non-relationship fields except those in `hide_fields` are shown in the generated OpenAPI specification."
570-
],
571-
show_relationships: [
572-
type: {:list, :atom},
573-
doc:
574-
"A list of relationships to show in the JSON:API response and generated OpenAPI specification. If not specified, all public relationships are allowed in responses, and all public relationships except those in `hide_fields` are shown in the generated OpenAPI specification."
569+
"A list of fields to show in the JSON:API response and generated OpenAPI specification. Applies to attributes, relationships, calculations, and aggregates. If not specified, all public fields are allowed in responses, and all public fields except those in `hide_fields` are shown in the generated OpenAPI specification."
575570
],
576571
derive_sort?: [
577572
type: :boolean,

0 commit comments

Comments
 (0)