If you want to get the nice json-like syntax for your configuration record, you need to implement a separate class which contains a set of methods that act on the Configuration Record that you created previously - one for each keyword that you want.
If you need have not built your own computation expression before, here are some background resources for you:
We will not cover the inner details of creating a Computation Expression (CE) here. For now, just know that a CE is a basic class (yes, like a C# class) that is very similar to an immutable fluent API you might see in C#, except that in F# you can expose each fluent method as what looks like a new keyword.
To get started the only member you need to implement is the Yield
method, which returns the “default” value of your record (i.e. before any fluent methods or keywords have been called).
// Builder.ContainerRegistry.fs
type ContainerRegistryBuilder() =
/// Required - creates default "starting" values
member _.Yield _ =
{ Name = ResourceName.Empty
Sku = Basic
AdminUserEnabled = false }
[<CustomOperation "name">]
/// Sets the name of the Azure Container Registry instance.
member _.Name (state:ContainerRegistryConfig, name) = { state with Name = ResourceName name }
[<CustomOperation "sku">]
/// Sets the name of the SKU/Tier for the Container Registry instance.
member _.Sku (state:ContainerRegistryConfig, sku) = { state with Sku = sku }
[<CustomOperation "enable_admin_user">]
/// Enables the admin user on the Azure Container Registry.
member _.EnableAdminUser (state:ContainerRegistryConfig) = { state with AdminUserEnabled = true }
Each keyword has a similar set of steps required:
state
object, which represents your configuration record. The implementation should perform some update to the state and return back the newly-updated state. Don’t worry about “where” the state goes - the F# CE will “thread” the state between calls for you.CustomOperation
attribute; the string value passed to it will become the keyword. Use _
to separate words of the keyword e.g. enable_admin_user
.///
comment on the method for intellisense to guide users.Now you can create members on the builder that appear as custom operators in your resource CE. In each member you build up the state of the resource configuration you created in the previous step.
Firstly, create a single static instance of the ContainerRegistryBuilder
class that you just made:
let containerRegistry = ContainerRegistryBuilder()
Now, you can create Container Registries anywhere using the keyword syntax:
/// myRegistry is of type ContainerRegistryConfig
let myRegistry = containerRegistry {
name "my-registry"
sku Basic
enable_admin_user
}
You can create parameterless keywords by simply only taking in the state argument e.g. enable_admin_user
above.
You can take in multiple arguments by simply putting a comma after each additional argument. They will be consumed by the user with spaces.
You can provide multiple overloads for a keyword. However, each overload must take in the same number of arguments. Do not re-apply the CustomOperation
attribute - simply provide multiple methods with the same name.