Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-export imported elements #13670

Open
jrobins-tfa opened this issue Mar 21, 2024 · 5 comments
Open

Re-export imported elements #13670

jrobins-tfa opened this issue Mar 21, 2024 · 5 comments
Labels
enhancement New feature or request Needs: Upvote This issue requires more votes to be considered

Comments

@jrobins-tfa
Copy link

I've run into an issue around user-defined types, which is that I can only export them up one level of consumption, and that's not always enough. As an example, suppose I have the following modules:

firstModule.bicep:

@export()
type firstType = {
  propX: string
  propY: int
}
param firstParam firstType

....

secondModule.bicep:

@export()
type secondType = {
  propA: string
  propB: int
}
param secondParam secondType

....

compositeModule.bicep:

import {firstType} from 'firstModule.bicep'
import {secondType} from 'secondModule.bicep'

param firstParam firstType
param secondParam secondType

module firstMod 'firstModule.bicep' = {
  name: 'firstMod'
  params: {
    firstParam: firstParam
  }
}

module secondMod 'secondModule.bicep' = {
  name: 'secondMod'
  params: {
    secondParam: secondParam
  }
}

So far, so good. I reuse the types to ensure that the params passed into my composite module have the same type as the individual modules those params will be passed along to.

The problem is that I want to share compositeModule.bicep with my consumers by publishing it to a private registry, and I don't want to publish firstModule.bicep or secondModule.bicep (because nobody should be directly using those modules). I want my consumers to be able to reuse the same user-defined types, but they don't have access to them - they're not exported from compositeModule.bicep, and the consumer doesn't have access to firstModule.bicep or secondModule.bicep.

I know that I could separate out the types into a separate file or two, and publish that/those file(s) to the registry, but this decouples the type from the content it's related to, which I don't really like as a solution.

What I would love to see is the ability to re-export imported elements. If I could do something like this in compositeModule.bicep:

@export()
import {firstType} from 'firstModule.bicep'
@export()
import {secondType} from 'secondModule.bicep'

And then my consumer could get those types from compositeModule.bicep without even needing to know that those types originated in another module. This would make these types more reusable without having to completely detach them from the content they're related to. It also provides a level of encapsulation because the consumer doesn't need to know what's going on under the hood in compositeModule.bicep.

I'm sure there's some complexity that will come into play with aliases for imports, especially if multiple imports with different aliases have same-named elements, but that feels like it should be solvable.

@sgebb
Copy link

sgebb commented Mar 27, 2024

Had the exact same need, so far solving it by having a separate types.bicep file for each module. In my registry i'll have bicep/servicebus:module and bicep/servicebus:types to make it clear that these are the types you need to import to use the module.

@marsontret
Copy link

This sounds interesting. What's a scenario where a user would reuse the custom types declared in the published module?

@jrobins-tfa
Copy link
Author

This sounds interesting. What's a scenario where a user would reuse the custom types declared in the published module?

Our scenario is that our consumers (development teams who are deploying applications to Azure) generally create a Bicep template that pulls together all of the components they need, and then set up parameter files for each environment. So a team deploying a webapp might have a template myApp.bicep something like:

param foo object
param bar object

module kv 'br:...keyvault' = {
  params: {
    foo: foo
  }
}

module appService 'br:...appservice' = {
  params: {
    bar: bar
  }
}

And then they could have param files myApp.qa.bicepparam, myApp.prod.bicepparam, etc.

The problem is that because foo and bar are just object type in myApp.bicep, they don't get any of the realtime validation, tooltips, and other benefits that come from having a custom type while working on the param files. If instead of objects, we had:

import {fooType} from 'br:...keyvault'
import {barType} from 'br:...appservice'
param foo fooType
param bar barType

Then the custom type would propagate out and would help out the developers creating the param files.

@stephaniezyen stephaniezyen added Needs: Upvote This issue requires more votes to be considered and removed Needs: Triage 🔍 labels Mar 27, 2024
@sgebb
Copy link

sgebb commented Mar 29, 2024

Just to add on my reason for wanting this.
I'm making a module for creating a service bus, where the service bus takes a list of Topics, each Topic consists of a list of Subscribers, and each Subscriber has a name plus the name of their keyvault so I can put the connection string in it. Because of how nested looping (doesn't) work in bicep I have to spread this out over three separate files to be able to create multiple resources per Subscriber.

This means I have Servicebus.bicep, referencing Topic.bicep, which references Subscription.bicep. I'm only publishing Servicebus.bicep to ACR. I can't dump all my types into Servicebus.bicep as that would create a cyclical reference (Subscription.bicep would have to reference Servicebus.bicep to gee Subscriber-type).

Now I want the consumers of my module to be able to create Topic and Subscriber objects when using the module.

param examplesub Subscriber = {
name: 'example'
vault: 'vault'
}

param exampletopicTopic = {
name: 'example'
subscribers: [mysub]
}

module sb '..' = {
name: 'sb'
params: {
topics: [exampletopic]
}
}

This way they can reference examplesub in multiple topics, and they get the benefits of a custom type. examplesub could be created as a var instead, but then you lose the assistance the type brings. i could also create the topic/subscriber directly under the module, then I get type assistance, but then I have no way of referencing the same object multiple times. Like I said I'm now putting the types in a separate types.bicep file which is published on it's own, but I would prefer if the types could be exposed directly through the module.

@Adunaphel
Copy link

My workaround for this is to store all user-defined types in their own files and importing those files whenever needed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Needs: Upvote This issue requires more votes to be considered
Projects
Status: Todo
Development

No branches or pull requests

5 participants