async-rest icon indicating copy to clipboard operation
async-rest copied to clipboard

Proper way to clear Reference parameters when yielding child resources

Open uberjay opened this issue 1 year ago • 0 comments

I'm wrapping an API which, like most, doesn't strictly adhere to REST. It's close enough that async-rest is a pretty good fit, however.

A pared down example of my situation:

class Representation < Async::REST::Representation
  def represent(metadata, attributes)
    resource = @resource.with(path: attributes[:id])

    representation.new(resource, metadata: metadata, value: {
      success: true, data: attributes
    })
  end
end

class VirtualMachineSummary < Representation
  def config
    # **** This is where the problem arises.
    self.with(VirtualMachineConfig, path: 'config')
  end
end

class VirtualMachines < Representation
  include Collection # for each, et al.

  def representation = VirtualMachineSummary
end

class Cluster < Representation
  def virtual_machines
    VirtualMachines.new(self.with(path: 'resources', parameters: { type: 'vm' }))
  end
end

class Client < Async::REST::Resource
  def cluster
    Cluster.new(self.with(path: 'cluster'))
  end
end

Any resource derived from Cluster#virtual_machines carries along a parameters value of { type: 'vm' }.

Now, there are many ways to slice this, but I'm wondering how you'd go about it. I fixed this by changing represent like so:

def represent(metadata, attributes)
  resource = @resource.with(path: attributes[:id])

  resource.reference.parameters.delete(:type) # <---- ADDED THIS

  representation.new(resource, metadata: metadata, value: {
    success: true, data: attributes
  })
end

Poking around the http-protocol implementation I'm left wondering what the right way to solve this is, and if the implementation of Reference#with is doing what's intended:

def with(path: nil, parameters: nil, fragment: @fragment, pop: false, merge: true)
  if @parameters
    if parameters and merge
      parameters = @parameters.merge(parameters)
    else
      parameters = @parameters
    end
  end

  if @query and !merge
    query = nil
  else
    query = @query
  end

  # ...

Given a Reference with parameters specified there's no way to override them. If merge is true, the supplied parameters will be merged with any existing params, but if it's false the supplied params are discarded. OTOH, if merge is false any existing @query value is ignored.

Reference also has a base method for generating a fresh ref with only the path -- perhaps I should use that in some way?

A little guidance would be helpful just to know how all of these pieces are intended to fit together.

Thank you! 😁

uberjay avatar Jan 21 '25 19:01 uberjay