Skip to content

Commit 6230e49

Browse files
committed
Allow hide_fields to override show_fields
1 parent 231baff commit 6230e49

7 files changed

Lines changed: 24 additions & 30 deletions

File tree

documentation/dsls/DSL-AshJsonApi.Resource.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ end
6767
| [`paginated_includes`](#json_api-paginated_includes){: #json_api-paginated_includes } | `list(atom \| list(atom))` | `[]` | A list of relationship paths that can be paginated when included via the `included_page` query parameter. Each entry can be either an atom (for top-level relationships) or a list of atoms (for nested paths). |
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 |
70-
| [`hide_fields`](#json_api-hide_fields){: #json_api-hide_fields } | `list(atom)` | `[]` | A list of fields to hide from generated API specifications and JSON:API responses. Applies to attributes, relationships, calculations, and aggregates. |
71-
| [`show_fields`](#json_api-show_fields){: #json_api-show_fields } | `list(atom)` | | A list of fields to show in generated API specifications and JSON:API responses. If not specified, all public fields are shown except those in `hide_fields`. |
70+
| [`hide_fields`](#json_api-hide_fields){: #json_api-hide_fields } | `list(atom)` | `[]` | A list of fields to hide from generated API specifications and JSON:API responses. Applies to attributes, relationships, calculations, and aggregates. Takes precedence over `show_fields`. |
71+
| [`show_fields`](#json_api-show_fields){: #json_api-show_fields } | `list(atom)` | | A list of fields to show in generated API specifications and JSON:API responses. If not specified, all public fields are shown except those in `hide_fields`. Fields in `hide_fields` are hidden even if listed here. |
7272
| [`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 |
7373
| [`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 |
7474
| [`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/resource/info.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ defmodule AshJsonApi.Resource.Info do
7575
Extension.get_opt(resource, [:json_api], :hide_fields, [], true)
7676
end
7777

78-
@doc "Fields to show in generated API specifications and JSON:API responses"
78+
@doc "Fields to show in generated API specifications and JSON:API responses. `hide_fields` takes precedence."
7979
def show_fields(resource) do
8080
Extension.get_opt(resource, [:json_api], :show_fields, nil, true)
8181
end

lib/ash_json_api/resource/resource.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,12 +561,12 @@ defmodule AshJsonApi.Resource do
561561
type: {:list, :atom},
562562
default: [],
563563
doc:
564-
"A list of fields to hide from generated API specifications and JSON:API responses. Applies to attributes, relationships, calculations, and aggregates."
564+
"A list of fields to hide from generated API specifications and JSON:API responses. Applies to attributes, relationships, calculations, and aggregates. Takes precedence over `show_fields`."
565565
],
566566
show_fields: [
567567
type: {:list, :atom},
568568
doc:
569-
"A list of fields to show in generated API specifications and JSON:API responses. If not specified, all public fields are shown except those in `hide_fields`."
569+
"A list of fields to show in generated API specifications and JSON:API responses. If not specified, all public fields are shown except those in `hide_fields`. Fields in `hide_fields` are hidden even if listed here."
570570
],
571571
derive_sort?: [
572572
type: :boolean,

lib/ash_json_api/resource/verifiers/verify_field_references.ex

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ defmodule AshJsonApi.Resource.Verifiers.VerifyFieldReferences do
2222

2323
validate_fields!(resource, :show_fields, show_fields, public_fields)
2424
validate_fields!(resource, :hide_fields, hide_fields, public_fields)
25-
validate_show_hide_overlap!(resource, show_fields, hide_fields)
2625

2726
:ok
2827
end
@@ -43,26 +42,4 @@ defmodule AshJsonApi.Resource.Verifiers.VerifyFieldReferences do
4342
end
4443
end)
4544
end
46-
47-
defp validate_show_hide_overlap!(_resource, nil, _hide_fields), do: :ok
48-
49-
defp validate_show_hide_overlap!(resource, show_fields, hide_fields) do
50-
overlap =
51-
show_fields
52-
|> MapSet.new()
53-
|> MapSet.intersection(MapSet.new(hide_fields || []))
54-
|> MapSet.to_list()
55-
|> Enum.sort()
56-
57-
unless Enum.empty?(overlap) do
58-
raise Spark.Error.DslError,
59-
module: resource,
60-
path: [:json_api],
61-
message: """
62-
Fields cannot appear in both `show_fields` and `hide_fields`.
63-
64-
Conflicting fields: #{inspect(overlap)}
65-
"""
66-
end
67-
end
6845
end

test/acceptance/field_visibility_test.exs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ defmodule Test.Acceptance.FieldVisibilityTest do
119119
type("visibility-show-post")
120120
includes([:visible_author, :extra_author])
121121
default_fields([:title, :summary, :secret_calc])
122-
show_fields([:title, :visible_author])
122+
hide_fields([:summary])
123+
show_fields([:title, :summary, :visible_author])
123124

124125
routes do
125126
base("/visibility_show_posts")
@@ -312,7 +313,9 @@ defmodule Test.Acceptance.FieldVisibilityTest do
312313
assert response.resp_body["data"]["type"] == "visibility-author"
313314
end
314315

315-
test "show_fields only exposes allowlisted fields", %{show_only_post: post} do
316+
test "show_fields only exposes allowlisted fields and hide_fields wins", %{
317+
show_only_post: post
318+
} do
316319
response =
317320
Domain
318321
|> get("/visibility_show_posts/#{post.id}", status: 200)
@@ -329,6 +332,18 @@ defmodule Test.Acceptance.FieldVisibilityTest do
329332
end
330333

331334
test "show_fields rejects non-allowlisted sparse fieldsets", %{show_only_post: post} do
335+
Domain
336+
|> get("/visibility_show_posts/#{post.id}?fields[visibility-show-post]=secret_calc",
337+
status: 400
338+
)
339+
|> assert_has_error(%{
340+
"code" => "invalid_field"
341+
})
342+
end
343+
344+
test "hide_fields rejects sparse fieldsets even when the field is in show_fields", %{
345+
show_only_post: post
346+
} do
332347
Domain
333348
|> get("/visibility_show_posts/#{post.id}?fields[visibility-show-post]=summary", status: 400)
334349
|> assert_has_error(%{

test/acceptance/json_schema_test.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ defmodule Test.Acceptance.JsonSchemaTest do
199199
type("hidden-json-post")
200200
default_fields([:name, :secret, :secret_calc])
201201
hide_fields([:secret, :secret_calc, :hidden_author])
202+
show_fields([:name, :secret, :secret_calc, :visible_author, :hidden_author])
202203

203204
routes do
204205
base("/hidden_json_posts")

test/acceptance/open_api_test.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ defmodule Test.Acceptance.OpenApiTest do
316316
paginated_includes([:visible_author, :hidden_author])
317317
default_fields([:name, :secret, :secret_calc])
318318
hide_fields([:secret, :secret_calc, :hidden_author])
319+
show_fields([:name, :secret, :secret_calc, :visible_author, :hidden_author])
319320

320321
routes do
321322
base("/hidden_spec_posts")

0 commit comments

Comments
 (0)