ash-project / ash_json_api

The JSON:API extension for the Ash Framework
https://hexdocs.pm/ash_json_api
MIT License
55 stars 41 forks source link

Better error messages when attempting to fetch a non-public field in a request #167

Closed sevenseacat closed 1 month ago

sevenseacat commented 1 month ago

Describe the bug

When attempting to fetch a field that is not marked as public? true, a confusing error is generated.

To Reproduce

The Tunez.Music.Artist resource:

  json_api do
    type "artist"

    routes do
      base "/artists"
      get :read
    end
  end

  attributes do
    uuid_primary_key :id

    attribute :name, :string do
      allow_nil? false
      public? false # <--- fetching this field
    end
  end

The request:

http://localhost:4000/api/artists/4fad50ae-9f07-49c1-a04a-560477a5d47d?fields=name

The error:

[debug] Processing with TunezWeb.JsonAPIRouter
  Parameters: %{"fields" => "name"}
  Pipelines: [:api]
warning: the following fields are unknown when raising AshJsonApi.Error.InvalidField: [source_parameter: "fields", detail: "Invalid field for type artist: name"]. Please make sure to only give known fields when raising or redefine AshJsonApi.Error.InvalidField.exception/1 to discard unknown fields. Future Elixir versions will raise on unknown fields given to raise/2
  (ash_json_api 1.2.0) lib/ash_json_api/error/invalid_field.ex:6: AshJsonApi.Error.InvalidField."exception (overridable 1)"/1
  (ash_json_api 1.2.0) lib/ash_json_api/error/invalid_field.ex:6: AshJsonApi.Error.InvalidField."exception (overridable 2)"/1
  (ash_json_api 1.2.0) lib/ash_json_api/request.ex:412: anonymous fn/5 in AshJsonApi.Request.add_fields/4
  ...

[info] Sent 500 in 31ms
[error] ** (KeyError) key :detail not found in: %AshJsonApi.Error.InvalidField{
  type: nil,
  field: nil,
  parameter?: nil,
  splode: nil,
  bread_crumbs: [],
  vars: [],
  path: [],
  stacktrace: #Splode.Stacktrace<>,
  class: :invalid
}
    (ash_json_api 1.2.0) lib/ash_json_api/error/invalid_field.ex:35: AshJsonApi.ToJsonApiError.AshJsonApi.Error.InvalidField.to_json_api_error/1
    (ash_json_api 1.2.0) lib/ash_json_api/error/error.ex:37: AshJsonApi.Error.to_json_api_errors/4
    (ash_json_api 1.2.0) lib/ash_json_api/request.ex:148: anonymous fn/4 in AshJsonApi.Request.add_error/4
    (elixir 1.17.0) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ash_json_api 1.2.0) lib/ash_json_api/request.ex:94: AshJsonApi.Request.from/6
    (ash_json_api 1.2.0) lib/ash_json_api/controllers/get.ex:19: AshJsonApi.Controllers.Get.call/2

(The warning is a Elixir 1.17 thing I think)

Expected behavior

The user should get back an error that they've requested something invalid.

When you submit a create request with invalid attributes, you get back an error like:

{
  "errors": [
    {
      "code": "invalid_body",
      "id": "0eff72a3-9744-45ea-b382-9a663bb96947",
      "meta": {},
      "status": "400",
      "title": "InvalidBody",
      "source": {
        "pointer": "data/attributes/invalid_field"
      },
      "detail": "Expected only defined properties, got key [\"data\", \"attributes\", \"invalid_field\"]."
    }
  ],
  "jsonapi": {
    "version": "1.0"
  }
}

Something similar maybe?

The JSON:API spec is not clear on what should be returned.

Runtime