ash-project / ash_json_api

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

Cannot POST with JSON:API structured data to create an entry with a relationship, "Expected only defined properties" #48

Closed Faheetah closed 3 years ago

Faheetah commented 3 years ago

Describe the bug A clear and concise description of what the bug is. If you are not sure if the bug is related to ash or an extension, log it with ash and we will move it. Following the instructions for Getting started with Ash and Phoenix which adds ash_json_api, when trying to POST to create a tweet and associate it with a user,

To Reproduce

Follow the instructions, or just clone the repo where I pushed up my code

https://github.com/faheetah/ash_my_app

Create a user, get the ID, then send a POST, the following snippet returns error "Expected only defined properties, got key [\"data\", \"relationships\", \"user\"]." despite conforming to JSON:API structure

user_id = Ash.Changeset.new(MyApp.User, %{email: "a@localhost"}) |> MyApp.Api.create! |> Map.get(:id)

tweet_data = %{data: %{attributes: %{body: "body", public: false}, relationships: %{user: %{data: %{id: user_id, type: "user"}}}, type: "tweet"}}

HTTPoison.post!("http://localhost:4000/api/tweets", Poison.encode!(tweet_data), [{"Content-type", "application/vnd.api+json"}]).body |> Poison.decode

Also adding the following:

action :create do
  argument :user, :map, allow_nil?: false #arguments are sent with attributes in json:api
  # change is like `plug` but for resource actions
  # `manage_relationship` is documented in `Ash.Changeset` and supports *tons* of options
  # you can read more about both in the docs
  change manage_relationship(:user, type: :replace)
end

Then using the following for the POST payload gives "detail" => "Expected only defined properties, got key [\"data\", \"attributes\", \"user\"]."

tweet_data = %{data: %{type: "tweet", attributes: %{body: "body", public: false, user: user_id}}}

Expected behavior

Creates a tweet associated to the user

** Runtime

Additional context

Referencing conversation: https://discord.com/channels/711271361523351632/799097774523547669/830259720245608458

Faheetah commented 3 years ago

https://github.com/ash-project/ash_json_api/blob/master/test/acceptance/post_test.exs#L69

I did try applying this line to MyApp.Tweet and it makes it work

    create :create do
      accept([:id, :body, :public, :user])
    end
zachdaniel commented 3 years ago

Thank you for the very detailed report!

zachdaniel commented 3 years ago

Alright, the fix for this has been released as version v0.28.0. Now ash_json_api does not accept relationship changes, no matter what is in the accept list (which is only for what attributes should be accepted, so that was a bug in ash_json_api).

See the relationship_arguments in the documentation for more information on using manage_relationship arguments in the relationships key: https://hexdocs.pm/ash_json_api/0.28.0/AshJsonApi.Resource.html

However, if you prefer the simpler variation of just accepting the relationship in the attributes, that should work as well.