Angular, Azure Storage, and Function Proxies - Oh My!

As I was working on the Securing Azure Functions with Azure Active Directory series, I wanted a simple way to test the application and OAuth flows in Azure. This seemed like a perfect time to try out the use of Azure Blob Storage for hosting static files and using Azure Function Proxies to deliver the Angular app. As a bonus, I got to learn a bit about integrating the process in Visual Studio Team Services (VSTS) build using the Azure CLI VSTS Task.

The Required Azure Components

Obviously we will need some Azure components. The Azure CLI and the snippets/scripts below get this part done quickly. If you don't have the Azure CLI, go get it now. The script below will enable us to have the storage we need to host our Angular app, and the Function App for our proxies to our static content.

# Show the current Azure Subscription, you may have to use az login  
az account show --verbose -o jsonc

az group create --name AngularAppRG --location eastus --output jsonc

az storage account create --name ngfuncappstore --resource-group AngularAppRG --location eastus --sku Standard_LRS --output jsonc 

az functionapp create --name AngularFuncAppProxy --resource-group AngularAppRG --storage-account ngfuncappstore --consumption-plan-location eastus --output jsonc   

We have what we need for the storage and proxies, but we need an Angular app to test this with. Use the Angular CLI to create the most basic application. The following will scaffold out the application. We only need a basic application for this post. I'll leave the complicated app as an exercise for the reader.

ng new NGFuncApp

Once we have the basic application created, add an image or a json file to the /src/assets folder just to simulate some additional resources. This is only to show some of the power of the Azure Function Proxies and of the VSTS Azure CLI Task a bit later.

Configure Blob Containers

Azure Blob Storage will serve our static Angular application files so we need to configure some containers that allow public access. First, we need to configure a $root container. This is a special container that will enable us to reference files in this container without the container name in the url. In addition to the $root container, we need an assets container. Both of these containers can be configured in the Azure Portal, but let's keep the trend of using the Azure CLI. The most important option when creating these containers is the --public-access blob parameter. This ensures that the blobs will be accessible via http.

az storage container create --name  "${root_container}"   --account-name $AZURE_STORAGE_ACCOUNT --account-key $AZURE_STORAGE_ACCESS_KEY --public-access blob
...
az storage container create --name  "${assets_container}" --account-name $AZURE_STORAGE_ACCOUNT --account-key $AZURE_STORAGE_ACCESS_KEY --public-access blob

And to remove the storage containers, just two lines are needed.

az storage container delete --name "$root_container" --account-name $AZURE_STORAGE_ACCOUNT --account-key $AZURE_STORAGE_ACCESS_KEY --verbose
...
az storage container delete --name "$assets_container" --account-name $AZURE_STORAGE_ACCOUNT --account-key $AZURE_STORAGE_ACCESS_KEY --verbose

The full configureNGStorage.sh and removeNGStorage.sh scripts are available as gists.

Configure the Function Proxies

We have an Angular application, a storage account to hold our application files, and now we need to configure the Function Proxies to serve our content. The image below shows configuring the initial proxy. This is for the root url and will point to our index.html file from our Angular application.

Create Base Url Proxy

We also need two more proxies for our content in the $root container and the assets container. You can continue using the "New Proxy" screen, or you can click the Advanced Editor link at the top left of the page. This will open the proxies.json file for the Function App in the App Service Editor. You can then edit the proxies definition by hand.

proxies.json

Notice that you can mix and match static paths and route variables for route templates. The route values will even be passed to the actual backend uri. This is really powerful stuff.

Build and Deploy our Angular Application

Now we can build our application. Using the Angular CLI, build the application in production mode. This will create the /dist folder with the build output and the assets we added. Then we can call the configureNGStorage.sh script (be sure to add a file to assets if you run the shell script or it will fail in the next step - hey, it's a blog post not bullet proof!). We need to provide the storage account name and a storage account key to the script.

$ ng build --prod && ./configureNGStorage.sh -a ngfuncappstore -k tHmDFQVSKSL2RyoBE5BKm6Kr+q4yJhbyHh4iC21ws4vhDgPA1vom2/kAaAKOZIRRmsMF4ZN8RCzHL4zNvDjtUw==

Once the script is done, we'll have our files at the root of /dist copied to the $root containers and assets respectively.

StorageExplorer

And finally we can visit the Function proxy url and see our application.

NGApp

Integrate into a VSTS Build

This is all goodness, but DevOps is the new hotness, and deploying from your desktop is not necessarily a best practice (end sarcasm). To take this a little bit further, I wanted to extend the Deploying Angular to Azure post from John Papa and put this into a build in Visual Studio Team Services.

John Papa's blog post provides some great detail, but his post and build process uses node and an App Service to provide the Angular application. We can certainly leverage the initial steps from John's post, including the VSTS Tasks to install the Angular CLI, install the project, and build the angular application. However, we want to clean the storage containers and then copy the updated content to the containers once Angular builds.

I thought I could reuse the shell scripts and be done quickly, but the Azure CLI VSTS Task did not seem to support the shell scripting options (apparently, it does if you are on a Linux build, but I did not try this). On to Plan Z. We can still use the Azure CLI, but since we are on a Windows host, we just have to use a batch file syntax.

To extend John Papa's build, we create some custom variables for our storage account information, the container names, and where our assets will be during the build. I am using the inline secret options here, but you may want to use Azure Key Vault in a more robust build.

Then we create an Azure CLI task that removes the containers from our storage account using our variables as input Arguments.

call az storage container delete --name "$root" --account-name "$(azurestorageaccount)" --account-key "$(azurestoragekey)" 
call az storage container delete --name "assets" --account-name "$(azurestorageaccount)" --account-key "$(azurestoragekey)"

Now we can build the application and once the application is complete, we call another Azure CLI task that will loop over our output and push the content to Azure blob storage. The tricky bit here was remembering the old for loop in a batch file! I won't lie, sadly that took me a few minutes.

VSTS Build

And there you have a build that will update your storage account and push your application updates as you update you app.

Wrapping Up

Using Azure Function Proxies and Blob Storage was a great learning exercise for both prototyping a SPA and mocking out the API. This seems like a really rapid way to prototype a SPA app, and use Azure Functions to build an application and API. There are many more options using Azure Function Proxies and this post only shows a couple of the options. One of the best features of Azure Function Proxies is overriding responses for your API that might be under development or even design, and replacing them with the actual end points once coded. Pretty sweet!

Keep in mind that this is not likely a production option for most applications. No root domain options are available, so *.azurewebsites.net is your primary option. There are other options like CloudFlare (this site uses that too!), but you will likely want to use an Azure AppService if you go this route (maybe a topic for another day). This could be a production option if you are creating internal applications, or applications that are secured with your Azure Active Directory. I'll leave that up to you.

HTH - let me know what you think by leaving a comment below.

Tweet Post Share Update Email

My name is Pete Skelly. I write this blog. I am the Director of Technology and Principal Consultant at ThreeWill, LLC in Alpharetta, GA.

Tags:
angular functions azure vsts
comments powered by Disqus