ash icon indicating copy to clipboard operation
ash copied to clipboard

Require `opts` to be passed to `define`’d code interface

Open RoyalIcing opened this issue 7 months ago • 3 comments

Is your feature request related to a problem? Please describe. Is there any way with a code interface to require that opts are passed? I want opts to be required as we always want tenant and actor to be passed in (or in the future world, scope to be passed).

This would mean given define :create_agreement, action: :create on a domain, that create_agreement/2 is defined but create_agreement/1 is not. I want calling create_agreement/1 to be a compile-time error.

Describe the solution you'd like Pass in require_opts?: true.

Describe alternatives you've considered Some sort of post-compile callback on the module to override the defined functions to error when not passing opts. Probably fragile.

Express the feature either with a change to resource syntax, or with a change to the resource interface

require_opts?: true added on the resource:

resources do
  resource MyApp.Agreement, require_opts?: true do
    define :create_agreement, action: :create
    define :read_agreements, action: :read
    define :update_agreement, action: :update
    define :destroy_agreement, action: :destroy
  end
end

or on each define:

resources do
  resource MyApp.Agreement do
    define :create_agreement, action: :create, require_opts?: true
    define :read_agreements, action: :read, require_opts?: true
    define :update_agreement, action: :update, require_opts?: true
    define :destroy_agreement, action: :destroy, require_opts?: true
  end
end

Additional context This is in a multi-tenanted app so I always want the tenant to be passed, and also the actor to be required.

RoyalIcing avatar May 07 '25 06:05 RoyalIcing

There is not currently a way. I'm open to ideas on this front, but there are a few considerations, and its an API I want to be extremely careful with. Like there are so many ways to solve the specific need or a generic need

i.e require_tenant?: true, require_options: [:tenant], validate_options: &require_tenant?/1, transform_inputs: fn args, opts -> {args, opts} end etc.

One thing I could actually see an argument for is that maybe this should just be literally automatic. We can tell when resources require a tenant. We'd have to make it opt-in via a backwards compatibility configuration, but why should we ever let you call a code interface for an action that we know requires a tenant without a tenant?

zachdaniel avatar May 07 '25 21:05 zachdaniel

Yes I agree, you ought to be able to say “this requires a tenant to be passed, as it will always error otherwise”.

I’d also ideally like to be able to say “this requires an actor”. I’m even happy for authorize?: false to not work then.

RoyalIcing avatar May 07 '25 23:05 RoyalIcing

The request will still always fail, right? i.e you don't have a request that is somehow allowing reading w/o a tenant despite requiring a tenant correct? The main thing here is just what is signaled by the options being, well, optional.

zachdaniel avatar May 09 '25 11:05 zachdaniel