Building a serverless web app
In this walkthrough tutorial, you will deploy a simple web application that enables users to upload their images and automatically get captions describing them. The application will present an HTML-based user interface displaying the list of images already uploaded (after signing in), all managed with a serverless backend.
The application uses Blob Storage (both for web static content and images/thumbnails), Azure Functions, Logic Apps, Cosmos DB, Computer Vision, and Azure Active Directory as pictured below:
What is covered in this lab?
- Create an Azure Storage account and configure containers to host static websites and images
- Create an Azure Function for uploading images to blob storage
- Resize images using Azure Functions
- Store image metadata in Cosmos DB
- Use Cognitive Services Vision API to auto-generate image captions
- Add authentication
In order to complete this lab you will need an Azure subscription. Please see the prerequisite section for more details. If you don't have an Azure subscription, create a free account before you begin.
Setting up the environment
Prerequisites for the lab
Microsoft Azure Account: You will need a valid and active Azure account for this lab. If you do not have one, you can sign up for a free trial
If you are a Visual Studio Active Subscriber, you are entitled for a $50-$150 credit per month. You can refer to this link to find out more including how to activate and start using your monthly Azure credit.
If you are not a Visual Studio Subscriber, you can sign up for the FREE Visual Studio Dev Essentials program to create Azure free account (includes 1 year of free services, $200 for 1st month).
You will perform all the steps in this lab in your web browser using the Azure Portal and Azure Cloud Shell. Azure Portal is a browser-based user interface. Cloud Shell provides a command line experience for managing resources in Azure.
Log in and configure Cloud Shell
Log in to the azure portal using your subscription credentials.
Open a Cloud Shell instance by clicking on its icon located in the upper right of the portal.
Select Bash (Linux).
Before Cloud Shell can be used for the first time, you need to configure it with a Storage account to persist files you created. Click on Show advanced Settings.
Enter the following values (note that your values may differ than the screenshot).
Name Value Cloud Shell region East US Resource group Use existing (first-serverless-app-xxxxx) Storage account Use existing (choose the existing account) File share Create name (name it fileshare) Click Create storage to create the file share used by Cloud Shell.
Create a web app in Blob Storage
In this exercise, you will create a blob storage account and a container to host files for a static website. You will upload the static files and access the single page application (SPA) directly from blob storage.
Create a Storage account
A Storage account is an Azure resource that allows you to store tables, queues, files, blobs (objects), and virtual machine disks.
In Azure, a Resource Group is a container that holds related Azure resources for ease of management. Create a resource group with the name first-serverless-app.
The static content (HTML, CSS, and JavaScript files) for this tutorial will be hosted in Blob Storage. Blob Storage requires a Storage account. Create a general purpose V2 Storage account named webstorage in the resource group.
Note: As resource names should be unique across all of Azure, provide unique name for your resources. For any step in this lab replace webstorage-name placeholder with your storage account name.
az storage account create -n <webstorage-name> -g first-serverless-app --kind StorageV2 -l eastus --https-only true --sku Standard_LRS
By default, running an
az
command returns information in JSON format.Create a Blob container named $root in the Storage account and allow its blobs to be publicly accessible. $root is a special container that allows files to be accessible at the root URL.
az storage container create -n \$root --account-name <webstorage-name> --public-access blob
Upload web application
The source files for building this tutorial are located in a GitHub repository. Ensure you are in your home directory in Cloud Shell and clone this repository.
cd ~
git clone https://github.com/Azure-Samples/functions-first-serverless-web-application source
The repository will be cloned to
~/source
.The client-side web application is located in the www folder and is built using the Vue.js JavaScript framework. Change into the folder and run npm commands to install the application's dependencies and build the application.
Note: it is perfectly normal to receive a server error that it is unable to load nuxtjs stats.
cd ~/source/www
npm install
npm run generate
The application is generated at
~/source/www/dist
.Change the current directory to dist and upload the application to the Blob container.
cd ~/source/www/dist
for file in *.*; do az storage blob upload -c \$root --account-name <webstorage-name> -f $file -n $file; done
az storage container create -n nuxt --account-name <webstorage-name> --public-access blob
az storage blob upload-batch -s nuxt -d nuxt --account-name <webstorage-name>
Note: The above instructions create a second container named nuxt and upload the contents of the nuxt folder. A recently released feature in Storage no longer requires this step. This lab will be updated to reflect this change.
Query the URL to the application.
az storage blob url -c \$root -n index.html --account-name <webstorage-name> -o tsv | sed 's/\$root\///'
Open the URL in a web browser to view the application.
Summary
In this exercise, you created a new storage account named webstorage and a blob container named $root that stores the static content for your web application and makes the content available publicly. Next, you will learn how to use a serverless function to upload images to Blob storage from this web application.
Upload images to blob storage with Azure Functions
In this exercise, you will create a container for storing and serving images. You will create a serverless function that provides a secure upload URL that the web application will use to upload images to the container.
Create a blob storage container for images
The application requires a separate storage container to upload and host images.
Ensure you are still logged into the Cloud Shell (bash). Create a new container named images in your storage account with public access to all blobs.
az storage container create -n images --account-name <webstorage-name> --public-access blob
Create an Azure Function app
Azure Functions is a service for running serverless functions. A serverless function can trigger on events such as an HTTP request or when a blob is created in a storage container.
An Azure Function app is a container for one or more serverless functions.
Create a new Azure Function app named fnapp in the resource group named first-serverless-app. Function apps require a Storage account; in this tutorial, you will use the existing storage account.
az functionapp create -n fnapp -g first-serverless-app -s <webstorage-name> -c eastus
For any step in this lab replace fnapp with your function app name.
Create an HTTP triggered serverless function
The photo gallery web application will make an HTTP request to a serverless function to generate a time-limited URL to securely upload an image to Blob storage. The function is triggered by an HTTP request and uses the Azure Storage SDK to generate and return the secure URL.
After the Function app is created, search for its name, fnapp, in the Azure Portal using the Search box and click to open it.
In the function app window's left hand navigation, hover over Functions and click + to start creating a new serverless function.
Click Custom function to see a list of function templates.
Find the HttpTrigger template and click the language to use (C# or JavaScript).
Use these values to create a function that generates a blob upload URL.
Setting Suggested value Description Language C# or JavaScript Select the language you want to use. Name your function GetUploadUrl Type this name exactly as shown so the application can discover the function. Authorization level Anonymous Allow the function to be accessed anonymously. Click Create to create the function.
C#
- When the function's source code appears, replace all of run.csx with the contents of csharp/GetUploadUrl/run.csx.
JavaScript
This function requires the
azure-storage
package from npm to generate the shared access signature (SAS) token required to build the secure URL. To install the npm package, click on the Function App's name on the left navigation and click Platform features.Click Console to reveal a console window.
Run the command
npm install azure-storage
in the console. It may take a minute or two to complete the operation.Click on the function name (GetUploadUrl) in the left navigation to reveal the function, replace all of index.js with the content of javascript/GetUploadUrl/index.js.
Click Logs below the code window to expand the logs panel.
Click Save. Check the logs panel to ensure the function is successfully saved and there are no errors.
The function generates what is called a shared access signature (SAS) URL that is used to upload a file to Blob storage. The SAS URL is valid for a short period of time and only allows a single file to be uploaded. Consult the Blob storage documentation for more information on using shared access signatures.
Add an environment variable for the storage connection string
The function you just created requires a connection string for the Storage account so that it can generate the SAS URL. Instead of hardcoding the connection string in the function's body, it can be stored as an application setting. Application settings are accessible as environment variables by all functions in the Function app.
In the Cloud Shell, query the Storage account connection string and save it to a bash variable named STORAGE_CONNECTION_STRING.
export STORAGE_CONNECTION_STRING=$(az storage account show-connection-string -n <webstorage-name> -g first-serverless-app --query "connectionString" --output tsv)
Confirm the variable is set successfully.
echo $STORAGE_CONNECTION_STRING
Create a new application setting named AZURE_STORAGE_CONNECTION_STRING using the value saved from the previous step.
az functionapp config appsettings set -n fnapp -g first-serverless-app --settings AZURE_STORAGE_CONNECTION_STRING=$STORAGE_CONNECTION_STRING -o table
Confirm that the command's output contains the new application setting with the correct value.
Test the serverless function
In addition to creating and editing functions, the Azure portal also provides a built-in tool for testing functions.
To test the HTTP serverless function, click on the Test tab on the right of the code window to expand the test panel.
Change the Http method to GET.
Under Query, click Add parameter and add the following parameter:
name value filename image1.jpg Click Run in the test panel to send an HTTP request to the function.
The function returns an upload URL in the output. The function execution appears in the logs panel.
Configure CORS in the function app
Because the app's frontend is hosted in Blob storage, it has a different domain name than the Azure Function app. For the client-side JavaScript to successfully call the function you just created, the function app needs to be configured for cross-origin resource sharing (CORS).
In the left navigation bar of the Function app window, click on the name of your function app.
Click on Platform features to view a list of advanced features.
Under API, click CORS.
Add an allow origin for the blob endpoint URL, omitting the trailing / (https://webstorage@lab.LabInstanceId.blob.core.windows.net)
Click Save to commit the change.
Modify the web app to upload images
The web app retrieves settings from a file named settings.js. You will modify the file using Cloud Shell to set the window.apiBaseUrl
variable to the URL of the Function app.
In the Cloud Shell, ensure that the current directory is the www/dist folder.
cd ~/source/www/dist
Query the function app's URL and store it in a bash variable named FUNCTION_APP_URL.
export FUNCTION_APP_URL="https://"$(az functionapp show -n fnapp -g first-serverless-app --query "defaultHostName" --output tsv)
Confirm the variable is correctly set.
echo $FUNCTION_APP_URL
To set the base URL of API calls to your function app, you will write the following line of code to settings.js.
window.apiBaseUrl = 'https://fnapp.azurewebsites.net'
You can make the change by running the following command or by using a command-line editor like VIM.
echo "window.apiBaseUrl = '$FUNCTION_APP_URL'" > settings.js
Confirm the file was successfully written.
cat settings.js
Upload the file to Blob storage.
az storage blob upload -c \$root --account-name <webstorage-name> -f settings.js -n settings.js
Test the web application
At this point, the gallery application is able to upload an image to Blob storage, but it cannot display images yet. You can verify an image is successfully uploaded by checking the contents of the images container in the Azure portal.
Obtain the URL of your application.
az storage blob url --account-name <webstorage-name> -c \$root -n index.html --output tsv | sed 's/\$root\///'
Open a new browser window and browse to the URL. Select an image file and upload it. The upload completes, but because we have not added the ability to display images yet, the app does not show the uploaded photo.
In the Cloud Shell, confirm the image was uploaded to the images container.
az storage blob list --account-name <webstorage-name> -c images -o table
Before moving on to the next tutorial, delete all files in the images container.
az storage blob delete-batch --account-name <webstorage-name> -s images
Summary
In this exercise, you created an Azure Function app and learned how to use a serverless function to allow a web application to upload images to Blob storage. Next, you learn how to create thumbnails for the uploaded images using a Blob triggered serverless function.
Resize Images with Azure Functions
In this exercise, you will create another storage container to store thumbnail images. Then you will create a serverless function to resize uploaded images and store them into the thumbnails container.
Create a blob storage container for thumbnails
The full size images are stored in a container named images. You need another container to store thumbnails of those images.
Ensure you are still logged into the Cloud Shell (bash). Create a new container named thumbnails in your storage account with public access to all blobs.
az storage container create -n thumbnails --account-name <webstorage-name> --public-access blob
Create a blob triggered serverless function
A serverless function can be triggered by an event such as the creation of an object in Blob storage. You can create a blob triggered function that generates an image thumbnail when an image is uploaded to the images container.
Triggers and bindings are a declarative way to define how a function is invoked and what data it works with. A trigger defines how a function is invoked. A function must have exactly one trigger. Triggers have associated data, which is usually the payload that triggered the function.
Bindings allow functions to input or output data or files.
The function we will create is triggered by a new object Blob storage. It also has a Blob output binding that saves the resized image in the thumbnails container.
Open your function app in the Azure Portal.
In the function app window's left hand navigation, hover over Functions and click + to start creating a new serverless function. If a quickstart page appears, click Custom function to see a list of function templates.
Find the BlobTrigger template and click it.
Use these values to create a function that creates thumbnails as images are uploaded.
Setting Suggested value Description Language C# or JavaScript Choose your preferred language. Name your function ResizeImage Type this name exactly as shown so the application can discover the function. Path images/{name} Execute the function when a file appears in the images container. Storage account information AZURE_STORAGE_CONNECTION_STRING Use the environment variable name previously created with the connection string. Click Create to create the function.
When the function is created, click Integrate to view its trigger, input, and output bindings.
Click New Output to create a new output trigger.
Select Azure Blob Storage and click Select. Note that you may have to scroll down to review the Select button.
Enter the following values.
Setting Suggested value Description Blob parameter name thumbnail The function will output the thumbnail to the parameter with this name. Use function return value No Path thumbnails/{name} The thumbnails will be output to a container named thumbnails. Storage account information AZURE_STORAGE_CONNECTION_STRING Use the environment variable name previously created with the connection string. JavaScript only
Click on Advanced editor in the top right corner of the window to reveal the JSON representing the bindings.
In the
blobTrigger
binding, add a property nameddataType
with a value ofbinary
. This configures the binding to pass the blob contents to the JavaScript function as binary data.
{ "name": "myBlob", "type": "blobTrigger", "direction": "in", "path": "images/{name}", "connection": "AZURE_STORAGE_CONNECTION_STRING", "dataType": "binary" }
Click Save to create the new binding.
Click on the ResizeImage function name on the left navigation to open the function's source code.
C#
The function requires a NuGet package called ImageResizer to generate the thumbnails. NuGet packages are added to C# functions using a project.json file. To create the file, click View Files on the right to reveal the files that make up the function.
Click Add to add a new file named project.json.
Copy the contents of /csharp/ResizeImage/project.json into the newly created file. Save the file. Packages are automatically restored when the file is updated.
Click on run.csx under View Files and replace its content with the content in /csharp/ResizeImage/run.csx.
JavaScript
This function requires the
jimp
package from npm to resize the photo. To install the npm package, click on the Function App's name on the left navigation and click Platform features.Click Console to reveal a console window.
Run the command
npm install jimp
in the console. It may take a minute or two to complete the operation.Click on the ResizeImage function name in the left navigation to reveal the function, replace all of index.js with the content of /javascript/ResizeImage/index.js.
Click Logs below the code window to expand the logs panel.
Click Save. Check the logs panel to ensure the function is successfully saved and there are no errors.
Test the serverless function
Obtain the URL of your application.
az storage blob url --account-name <webstorage-name> -c \$root -n index.html --output tsv | sed 's/\$root\///'
Open a new browser window and browse to the URL. Select an image file and upload it. The upload completes, but because we have not added the ability to display images yet, the app does not show the uploaded photo.
In the Cloud Shell, confirm the image was uploaded to the images container.
az storage blob list --account-name <webstorage-name> -c images -o table
Confirm the thumbnail was created in a container named thumbnails.
az storage blob list --account-name <webstorage-name> -c thumbnails -o table
Before moving on to the next tutorial, delete all files in the images and thumbnails containers.
az storage blob delete-batch --account-name <webstorage-name> -s images
az storage blob delete-batch --account-name <webstorage-name> -s thumbnails
Summary
In this exercise, you created a serverless function to create a thumbnail whenever an image is uploaded to a Blob storage container. Next, you will learn how to use Azure Cosmos DB to store and list image metadata.
Store image metadata with Azure Cosmos DB
In this exercise, you will create and use the Computer Vision API to generate captions for uploaded images.
Create a Computer Vision account
Microsoft Cognitive Services are a collection of services available to developers to make their applications more intelligent. The Computer Vision API is a serverless service that processes images using advanced algorithms and returns information about each image. It has a free tier that provides up to 5000 API calls per month.
Ensure you are still logged into the Cloud Shell. Create a new Cognitive Services account of kind ComputerVision with a unique name in your resource group. For the free tier, use S1 as the SKU.
az cognitiveservices account create -g first-serverless-app -n compvision --kind ComputerVision --sku S1 -l eastus
Create Function App settings for Computer Vision URL and key
To call the Computer Vision API, a URL and key are required.
Obtain the Computer Vision API key and URL and save them in bash variables.
export COMP_VISION_KEY=$(az cognitiveservices account keys list -g first-serverless-app -n compvision --query key1 --output tsv)
export COMP_VISION_URL=$(az cognitiveservices account show -g first-serverless-app -n compvision --query endpoint --output tsv)
Create app settings named COMP_VISION_KEY and COMP_VISION_URL, respectively, in the function app.
az functionapp config appsettings set -n fnapp -g first-serverless-app --settings COMP_VISION_KEY=$COMP_VISION_KEY COMP_VISION_URL=$COMP_VISION_URL -o table
Ensure the output contains the appropriate values.
Call Computer Vision API from ResizeImage function
You will modify the ResizeImage function to call the Computer Vision API to describe each uploaded image and save the description in Cosmos DB.
Open your function app in the Azure Portal.
C#
Using the left navigation, locate the ResizeImage function and open its code window.
Replace the code with the contents of /csharp/ResizeImage/run-module5.csx that uses
HttpClient
to call Computer Vision API and save its result in Cosmos DB.
JavaScript
This function requires the
axios
package from npm to make an HTTP call to the Computer Vision API. To install the npm package, click on the Function App's name on the left navigation and click Platform features.Click Console to reveal a console window.
Run the command
npm install axios
in the console. It may take a minute or two to complete the operation.Click on the function name (ResizeImage) in the left navigation to reveal the function, and then replace all of index.js with the contents of /javascript/ResizeImage/index-module5.js.
Click Logs below the code window to expand the logs panel.
Click Save. Check the logs panel to ensure the function is successfully saved and there are no errors.
Test the application
Obtain the URL of your application.
az storage blob url --account-name <webstorage-name> -c \$root -n index.html --output tsv | sed 's/\$root\///'
Open a new browser window and browse to the URL. Select an image file and upload it.
After a few seconds, the thumbnail of the new image should appear on the page. Hover over the image to see the description generated by Computer Vision.
Summary
In this exercise, you learned how to automatically generate captions for each uploaded image using Microsoft Cognitives Services' Computer Vision API. Next, you will learn how to add authentication to the application using Azure App Service Authentication.
Exercise 6: Add authentication (5 minutes)
Azure Functions is part of the Azure App Service platform. App Service Authentication allows you to quickly add authentication to your function app using one or more of the following services: Facebook, Twitter, Google, Microsoft Account, and Azure Active Directory.
For this exercise, you will configure your application to log in with Azure Active Directory.
Enable App Service Authentication
Open the function app you created earlier.
Under Platform features, click on Authentication/Authorization.
Select the following values:
Setting Suggested value Description App Service Authentication On Enable authentication. Action when request is not authenticated Log in with Azure Active Directory Select a configured authentication method (below). Authentication Providers See below See below Token store On Allow App Service to store and manage tokens. Allowed external redirect URLs https://webstorage@lab.LabInstanceId.blob.core.windows.net/index.html Add an entry for the URL of your application. Instructions for AAD (need tabs here for other social logins: Twitter, FB, Google, Microsoft)
Click on Azure Active Directory to reveal Azure Active Directory Settings.
Select Express as the Management Mode and fill in the following information.
Setting Suggested value Description Management mode Express, Create new AD app Automatically set up a service principal and Azure Active Directory authentication. Create app fnapp@lab.GlobalLabInstanceId Enter a unique application name. Click OK to save the Azure Active Directory settings.
Click Save to finish setting up App Service Authentication.
Modify the web app to enable authentication
In the Cloud Shell, ensure that the current directory is the dist folder.
cd ~/source/www/dist
To enable authentication in your web app, append the following line of code to settings.js.
window.authEnabled = true
Make the change by running the following command or by using a command-line editor like VIM.
echo "window.authEnabled = true" >> settings.js
Confirm the change was made to the file.
cat settings.js
Upload the file to Blob storage.
az storage blob upload -c \$root --account-name <webstorage-name> -f settings.js -n settings.js
Test the application
Obtain the URL of your application.
az storage blob url --account-name <webstorage-name> -c \$root -n index.html --output tsv | sed 's/\$root\///'
Open a new browser window and browse to the URL. Click Log in and log in.
Select an image file and upload it.
Summary
In this exercise, you learned how to enable authentication to the applcation using Azure App Service Authentication.
Congratulations!
Congratulations on building a serverless web app on Azure using: Azure Storage, Functions, Cosmos DB, and Cognitive Services
Have an issue with this section? If so, please give us some feedback so we can improve this section.