Use metadata to return additional information

Hi there!

I’m using ash_json_api and I’m trying to add metadata to the response of a create action, but it doesn’t seem to be included in the meta field. I’ve got the following relevant pieces in my resource:

 json_api do type "asset" routes do base "/assets" get :read index :read post :create end end actions do defaults [:read] create :create do # Set the current user as the owner of the asset change relate_actor(:user) # Create signed url for the asset metadata :signed_url, :string, allow_nil?: false change Swoop.Media.Changes.GeneratePresignedUrl end end 

In GeneratePresignedUrl I’m returning this in a after_action function:

 result = Ash.Resource.put_metadata(result, :signed_url, url) {:ok, result} 

But unfortunately after doing a POST to the endpoint with curl, I’m getting empty meta fields:

{"data":{"attributes":{},"id":"11700f40-c37b-4776-b3b0-7d1207cbb6d0","links":{},"meta":{},"relationships":{},"type":"asset"},"jsonapi":{"version":"1.0"},"links":{"self":"http://localhost:4000/api/json/assets"},"meta":{}} 

What am I missing?

Thanks in advance!

At the moment, action metadata isn’t translated to record meta in the JSON:API. Please open a feature request for this :slight_smile:

To accomplish what you want, you have two options:

  1. you can use the metadata option on the route to add route-level meta. This is done via a function of the various components of the request. This will be in the top level meta, not the record’s metadata. DSL: AshJsonApi.Resource — ash_json_api v1.4.9

  2. you can use a calculation instead of metadata:

calculate :signed_url, :string, fn records -> Enum.map(records, fn record -> signed_url(record) end) end 

This can then be requested in the fields parameter, i.e fields[type-name]=foo,bar,baz,signed_url.

Great, thanks! I’ll use one of those options for now and open a feature request.

Just out of curiosity, what is the metadata option on the actions used for?

Actually kept my code the same, but changed my create route to:

 post :create do metadata fn subject, result, request -> %{signed_url: result.__metadata__.signed_url} end end 

So that I possibly can reuse the metadata in other places than the route. But still curious to know if there may be other use cases :slight_smile:

The way you are attempting to use it is actually its intended use case :slight_smile: However, it just hasn’t been hooked up to ash_json_api yet. AshGraphql has a way to expose metadata in exactly that same way. It requires some adjustments to our open api schema generation logic, because we need to do one of three things:

  1. allow you to configure a special type name for the results of the action, i.e asset-with-url
  2. we have to add that meta to all types
  3. we have to keep meta as untyped “object”

Its a solvable problem, just hasn’t been implemented yet :slight_smile:

1 Like