DEV Community

Steve Bjorg for LambdaSharp

Posted on • Edited on

Emulating Fn::StartsWith in CloudFormation

Overview

CloudFormation has a limited number of intrinsic functions that can be combined in some interesting ways.

One of the intrinsic functions I wish existed is Fn::StartsWith. As the name implies, the objective is to check if a string begins with another string. While this operation doesn't exist natively, it can be constructed using the existing intrinsic functions.

Part 1 - Fn::Split

Fn::Split is an intrinsic function used to split a string into an array using a delimiter string. It's most commonly used to split on a punctuation mark, such a comma (,). One of the side effects of applying this function, is that the resulting array does NOT contain the delimiter string, which we can leverage.

Consider the following example:

!Split [ "world", "hello world!" ]
Enter fullscreen mode Exit fullscreen mode

Which produces this result.

[ "hello ", "!" ]
Enter fullscreen mode Exit fullscreen mode

As you can see, the word "world" is gone from the result.

Let's do this again using "hello" instead:

!Split [ "hello", "hello world!" ]
Enter fullscreen mode Exit fullscreen mode

We get:

[ "", " world!" ]
Enter fullscreen mode Exit fullscreen mode

Now the lightbulb is turning on. Indeed, when the first string of a Fn::Split operation is empty, it means the split operation found an occurrence of the delimiter string at the beginning. Let's use this!

Part 2 - Fn::Select and Fn::Equals

Fortunately, Fn::Split always returns an array of at least one element. This makes it safe to always access the first item in the returned array. We can use that to compare the value to an empty string.

!Equals [ !Select [ 0, !Split [ PREFIX, VALUE ], "" ]]
Enter fullscreen mode Exit fullscreen mode

Part 3 - Beware of empty strings

An empty string, split on any delimiter string, always produces an array with a single empty string in it. This gives us a false positive if we don't check for it.

!Not [ !Equals [ VALUE, "" ]]
Enter fullscreen mode Exit fullscreen mode

Final - Putting it all together

Combining the empty string check and the Fn::Split function gives us an implementation of Fn::StartsWith.

!And [ 
    !Not [ !Equals [ VALUE, "" ]],
    !Equals [ !Select [ 0, !Split [ PREFIX, VALUE ]], "" ]
]
Enter fullscreen mode Exit fullscreen mode

I hope you found this useful. If you know of other patterns to emulate missing functionality in CloudFormation, please leave a comment!

Happy Hacking!

Top comments (4)

Collapse
 
nimbusscale profile image
Joe

I tried the above, but found there was an issue with the !Equals clause as one of the closing brackets was in the wrong spot. I was able to get it to work as the following:

!Equals [!Select [ 0, !Split [ PREFIX, VALUE ]], ""]

Collapse
 
bjorg profile image
Steve Bjorg

Thanks for letting me know. I corrected the article.

Collapse
 
jacco profile image
Jacco Kulman

Hey there. Was trying to see if it is also possible to construct a Fn::EndsWith. Couldn't work one out because the !Select needs the last item instead of the first. Do you happen to know a similar trick for that?

Collapse
 
bjorg profile image
Steve Bjorg

It might be possible to approximate it if you allow for an upper-bound and you add a magic marker at the end. That way, you could incrementally do an Fn:::Contains operation (similar to Fn::StartsWith) and see if you reach the magic marker by itself.