Hey there, I'm having some trouble comprehending w...
# general
Hey there, I'm having some trouble comprehending what is the correct way to deal with nested InputT objects, as the Pulumi AI is really giving me mixed answers. (Note: This became a little long and probably unnecessarily convoluted, but I'm really just trying to find the correct way of getting the nested properties, when passing an output object as an input argument in another resource.) So, is there anyone who is able to enlighten me a little. If I have a
, that outputs an object of type
, then naturally the properties of the bucket are also of some type
. Now, if I want to use the bucket as
in some other resource, I seem to be unable to access the underlying properties of the bucket, such as id, name, etc. because the
does not allow me to do so. This is then where things gets a little weird for me. The type
has the
, which let's me access the values of an output. Apparently, the
type does not implement this method, as of version 3.98.0. However, the Pulumi AI is telling me both that I can, and that I can't, use apply on an input, sometimes also saying to convert the Input to an Output and then use apply, and then I'm not really sure what to think. So, is there way to access nest properties of an
without having to converting things back and forth, or am I mistaken for doing this and should only pass concrete types as inputs, as to unwrap my object to it's individual properties as output instead?
In typescript,
is defined as
type Input<T> = T | Promise<T> | Output<T>
usually I'd use
to force it into an
and then
since it also unwraps nested `Input`s
Also, if you just want to access a property, then you can let Pulumi lift it for you. For an object
of type
{ id: string }
, Pulumi will interpret
x.apply((o) => o.id)
, so you can omit using
@boundless-petabyte-41580 it's just feels odd that you gotta map the input to an output to access the underlying values, but maybe that's just me complaining and it's intended that way?
@little-cartoon-10569 but if the Output is of type
const bucket: Output<Bucket>
, where
Bucket := { name: Output<string> }
, which is the case when I return the entire bucket object from the
, and pass it as to a parameter
bucketInput: Input<Bucket>
is no longer reference-able because apparently
does not exist on
@most-napkin-55076 the
is mostly for accessing nested structures. It also coerces every
so you have a predictable interface to work with. Theoretically, to stay in input land you could implement something like
Copy code
function apply<T, T1>(input: Input<T>, f: (t: T) => Input<T1>): Input<T1>
but you'd need path-dependent types, since you don't know if the
you're working with has the same monad as
Re: it's just feels odd that you gotta map the input to an output to access the underlying values : You don't have to. That's a convenience because the alternative (to access them via Input<>) is harder! So generally, we do. Having a consistent interface like Output can really tidy up code; I'm been known to wrap hardcoded strings (or Promises) in
just to force consistency in the code.
Re: if the Output is of type const bucket: Output<Bucket> Outputs should (probably) never wrap anything that isn't a future value. By inference, Outputs should never wrap anything you create yourself, only things that have been returned from cloud APIs. You never need an
. Output only ever wrap primitives and arrays of primitives. And in some unfortunate cases, other Outputs or Inputs (though in my experience, those cases might have been able to be reduced to just primitives, with a bit more work in the provider classes).
I'm sure that with a little redesign, anywhere that's returning an
can be changed to return either a
or an
(being the ARN or bucket name), depending on requirements.
I see, I think I start to understand the design choices. The reason is just that we have the
, that wraps other resources, such as the
, as Output, and for me it would just be preferred to not having to unwrap all of the properties of each "child" resource, for then in turn having to pass multiple primitive values around to, potentially, a single resource, as is the case for me, because I have to use multiple properties of a
in a separate component. So it's not as much as I can't get it to work, it's more that the way that works, really feels to overcomplicate something that, from the outside at least, is pretty simple., But maybe the way to go is just to map Inputs to Outputs whenever they're reference objects and call it a day?
The ComponentResource can have a Bucket property, it doesn't need to be an Output<Bucket>.
Oh I see. It's because we're using the
to initialize the components, which returns a promise, but I guess that's really not mandatory then? (note, I didn't initially make this, I've just been expanding on it, so a lot of learning still)
I don't know what those are. If you're constructing resources in the normal way, you don't get a Promise.
Those two methods are some implementation for async initialization on resources. It's apperently optional, so not exactly sure when it's actually needed. Line 1029 and 1037 https://github.com/pulumi/pulumi/blob/035a502d86403d815059615a9c047ccccc2cbdd5/sdk/nodejs/resource.ts#L1029C12-L1029C12
Those are specifically for asynchronous data. Resources aren't data, so you won't be initializing them in there. It would be for things like the boot logs of a compute instance (which wouldn't be available until after the resource has been allocated and booted, potentially many minutes after the resource was created).