in reply to controlling what is returned, where.

Depending on the rest of the code, you might be able to stuff the
my $id = $self->query->param('id'); $self->param("object") = $self->get_obj($id) if $id;
in the setup() method.

Then you "only" need to do

sub foo { my $self = shift; my $object = $self->param("object") or return $self->get_id(); # ... the rest }
If you *always* need that object, you might do
sub cgiapp_prerun { # ... my $id = $self->query->param('id'); if (!$id) { return $self->prerun_mode('get_id'); } $self->param("object") = $self->get_obj($id); # ... }

which will automatically run the get_id mode unless an id is specified, so all other modes can be certain the object is available in $self->param("object").