{"id":17114377,"url":"https://github.com/anthonychu/functions-serverless-realtime-tutorial","last_synced_at":"2025-07-03T13:06:12.271Z","repository":{"id":68672601,"uuid":"164074654","full_name":"anthonychu/functions-serverless-realtime-tutorial","owner":"anthonychu","description":null,"archived":false,"fork":false,"pushed_at":"2019-01-18T19:10:54.000Z","size":3588,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-09T21:47:33.688Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anthonychu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-04T07:37:42.000Z","updated_at":"2020-02-18T14:55:34.000Z","dependencies_parsed_at":"2023-05-17T19:30:34.733Z","dependency_job_id":null,"html_url":"https://github.com/anthonychu/functions-serverless-realtime-tutorial","commit_stats":{"total_commits":10,"total_committers":2,"mean_commits":5.0,"dds":0.09999999999999998,"last_synced_commit":"bc1566e4074933900d2428022a39c22d48986c69"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/anthonychu/functions-serverless-realtime-tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonychu%2Ffunctions-serverless-realtime-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonychu%2Ffunctions-serverless-realtime-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonychu%2Ffunctions-serverless-realtime-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonychu%2Ffunctions-serverless-realtime-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anthonychu","download_url":"https://codeload.github.com/anthonychu/functions-serverless-realtime-tutorial/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonychu%2Ffunctions-serverless-realtime-tutorial/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263331769,"owners_count":23450155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T17:16:59.064Z","updated_at":"2025-07-03T13:06:12.248Z","avatar_url":"https://github.com/anthonychu.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Build a real-time serverless app with Azure Functions\n\n## Introduction\n\nIn this tutorial, you'll be building a serverless web app for displaying airline flight prices. The flight prices on the web page updates in real-time as prices are changed in the database. You'll then add authentication to the application and allow authenticated users to update the prices.\n\n### Technologies used\n\n* [Azure Storage](https://azure.microsoft.com/services/storage/?WT.mc_id=serverlesschatlab-tutorial-antchu)\n    - Host the static website for the frontend\n* [Azure Functions](https://azure.microsoft.com/services/functions/?WT.mc_id=serverlesschatlab-tutorial-antchu)\n    - Backend API for retrieving and modifying prices\n    - Logic to broadcast pricing changes in real-time\n* [Azure Cosmos DB](https://azure.microsoft.com/services/cosmos-db/?WT.mc_id=serverlesschatlab-tutorial-antchu)\n    - Store flight prices\n    - Trigger Azure Functions when data changes\n* [Azure SignalR Service](https://azure.microsoft.com/services/signalr-service/?WT.mc_id=serverlesschatlab-tutorial-antchu)\n    - Broadcast flight price updates to connected browsers using technologies such as WebSocket\n\n### Prerequisites\n\n\u003c!-- \u003e\u003e If you are using a prepared virtual machine for this lab, all prerequisites should already be installed. --\u003e\n\nThe following software is required to build this tutorial.\n\n* [Node.js](https://nodejs.org/en/download/) (Version 10.x)\n* [.NET SDK](https://www.microsoft.com/net/download?WT.mc_id=serverlesschatlab-tutorial-antchu) (Version 2.x, required for Functions extensions)\n* [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools) (Version 2)\n* [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=serverlesschatlab-tutorial-antchu) (VS Code) with the following extensions\n    * [Azure Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-node-azure-pack\u0026WT.mc_id=serverlesschatlab-tutorial-antchu)\n        - Includes Azure Functions and Azure Storage extensions\n* [http-server](https://www.npmjs.com/package/http-server)\n    * For running frontend web app locally\n    * Install using the command `npm install http-server -g`\n* [Postman](https://www.getpostman.com/) (optional, for testing HTTP Azure Functions)\n\n---\n\n## Create Azure resources\n\nYou will build and test the Azure Functions app locally. The app will access some services in Azure that need to be created ahead of time.\n\n\n### Log in to the Azure portal\n\n1. Go to the [Azure portal](https://portal.azure.com/) and log in with your credentials.\n\n\n### Create an Azure Cosmos DB account\n\n1. Click on the **Create a resource** (**+**) button for creating a new Azure resource.\n\n1. Under **Databases**, select **Azure Cosmos DB**.\n\n1. Enter the following information.\n\n    | Name | Value |\n    |---|---|\n    | Subscription | Select the subscription you want to use |\n    | Resource group | Create new - enter a new resource group name |\n    | Account name | A unique name for the Cosmos DB account |\n    | API | Core (SQL) |\n    | Location | Select a location close to you |\n    | Geo-redundancy | Disable |\n    | Multi-region writes | Disable |\n    \n    ![](media/create-cosmosdb.png)\n\n1. Click **Review and create**, then **Create**.\n\n\n### Create a Storage account\n\nWhile the Cosmos DB account is creating, create a Storage account.\n\n1. Click on the **Create a resource** (**+**) button for creating a new Azure resource.\n\n1. Under **Storage**, select **Storage account**.\n\n1. Enter the following information.\n\n    | Name | Value |\n    |---|---|\n    | Subscription | Select the same subscription as the Cosmos DB account |\n    | Resource group | Select the same resource group as the Cosmos DB account |\n    | Storage account name | A unique name for the Storage account |\n    | Location | Select a location close to you |\n    | Performance | Standard |\n    | Account kind | StorageV2 (general purpose v2) |\n    | Replication | Locally-redundant storage (LRS) |\n    | Access tier (default) | Hot |\n    \n1. Click **Review and create**, then **Create**.\n\n    ![](media/create-storage.png)\n\n\n### Create an Azure SignalR Service instance\n\nWhile the other resources are creating, create a SignalR Service instance.\n\n1. Click on the **Create a resource** (**+**) button for creating a new Azure resource.\n\n1. Search for **SignalR Service** and select it. Click **Create**.\n\n1. Enter the following information.\n\n    | Name | Value |\n    |---|---|\n    | Resource name | A unique name for the SignalR Service instance |\n    | Subscription | Select the same subscription as the other resources |\n    | Resource group | Select the same resource group as the resources |\n    | Location | Select a location close to you |\n    | Pricing Tier | Free |\n\n    ![](media/create-signalrservice-1.png)\n\n    ![](media/create-signalrservice-2.png)\n    \n1. Click **Create**.\n\n\n### Create a database and collection in Cosmos DB\n\nBefore creating the application, you will initialize the Cosmos DB account with a database and a collection. You will also seed it with some data.\n\n1. When the Cosmos DB account has been created, open it in the Azure portal.\n    \u003e One way to locate resources in the Azure portal is to search for it with the search bar.\n    \u003e\n    \u003e ![](media/find-cosmosdb.png)\n\n1. Select **Data Explorer**, create a database and collection.\n    1. Click **New Collection**.\n    1. Select **Create new** and enter **flightsdb** as the database id.\n    1. Select **Provision throughput** and enter a throughput value of **400**.\n    1. In **Collection id**, enter **flights**.\n    1. Enter a partition key of **/id**.\n    1. Click **OK** to create the database.\n\n    ![](media/create-cosmosdb-collection.png)\n\n1. In the Data Explorer, navigate to the newly created **flights** collection.\n\n1. Select the collection's **Documents**.\n\n1. Click on **New Document** and enter the following as the body of the document:\n\n    ```json\n    {\n        \"id\": \"68a912fd-fed7-aae1-9d7d-af3c4c9cfdaa\",\n        \"from\": \"SEA\",\n        \"to\": \"LAX\",\n        \"price\": 300\n    }\n    ```\n\n1. Click **Save** to create the document in the collection.\n\n    ![](media/create-cosmosdb-document.png)\n\n\n---\n\n\n## Initialize a function app\n\nNow that the Azure resources are created and Cosmos DB has been initialized, It's time to create the function app. You will create and run the function app locally on your computer. It will use the resources you have created in Azure.\n\nLater on in the tutorial, you will deploy the function app to Azure.\n\n\n### Create a new Azure Functions project\n\n1. In a new VS Code window, use `File \u003e Open Folder` in the menu to create and open an empty folder in an appropriate location. This will be the main project folder for the application that you will build.\n\n1. Using the Azure Functions extension in VS Code, initialize a Function app in the main project folder.\n    1. Open the Command Palette in VS Code by selecting `View \u003e Command Palette` from the menu (shortcut `Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n    1. Search for the \"Azure Functions: Create New Project\" command and select it.\n    1. The main project folder should appear. Select it (or use \"Browse\" to locate it).\n    1. In the prompt to choose a language, select **JavaScript**.\n\n    ![](media/new-function-app.png)\n\n\n\n### Install function app extensions\n\nThis tutorial uses Azure Functions bindings to interact with Azure Cosmos DB and Azure SignalR Service. These bindings are available as extensions that need to be installed using the Azure Functions Core Tools CLI before they can be used.\n\n1. Open a terminal in VS Code by selecting `View \u003e Terminal` from the menu (Ctrl-`).\n\n1. Ensure the main project folder is the current directory.\n\n1. Install the Cosmos DB function app extension.\n    ```\n    func extensions install -p Microsoft.Azure.WebJobs.Extensions.CosmosDB -v 3.0.3\n    ```\n\n1. Install the SignalR Service function app extension.\n    ```\n    func extensions install -p Microsoft.Azure.WebJobs.Extensions.SignalRService -v 1.0.0-preview1-10025\n    ```\n\n    ![](media/add-functions-extensions.png)\n\n\n### Configure application settings\n\nWhen running and debugging the Azure Functions runtime locally, application settings are read from **local.settings.json**. Update this file with the connection strings of the Cosmos DB account and the SignalR Service instance that you created earlier.\n\n\u003e Note that this file is excluded from source control by default. You will use environment variables and other settings in Azure to configure your function app in the cloud.\n\n1. In VS Code, select **local.settings.json** in the Explorer pane to open it.\n\n1. Replace the file's contents with the following.\n    ```json\n    {\n      \"IsEncrypted\": false,\n      \"Values\": {\n        \"AzureWebJobsStorage\": \"\u003cstorage-connection-string\u003e\",\n        \"AzureSignalRConnectionString\": \"\u003csignalr-connection-string\u003e\",\n        \"AzureCosmosDBConnectionString\": \"\u003ccosmosdb-connection-string\u003e\",\n        \"FUNCTIONS_WORKER_RUNTIME\": \"node\"\n      },\n      \"Host\": {\n        \"LocalHttpPort\": 7071,\n        \"CORS\": \"http://localhost:8080\",\n        \"CORSCredentials\": true\n      }\n    }\n    ```\n\n    * Replace `\u003cstorage-connection-string\u003e` with the Azure Storage account connection string. Obtain the value from the **Keys** page in the Azure portal for the Storage account you created; either the primary or secondary connection string can be used. This setting is required by Azure Functions runtime to coordinate executions between multiple function app instances.\n    * Replace `\u003csignalr-connection-string\u003e` with the Azure SignalR Service connection string. Obtain the value from the **Keys** page in the Azure SignalR Service resource in the Azure portal; either the primary or secondary connection string can be used.\n    * Replace `\u003ccosmosdb-connection-string\u003e` with the Azure Cosmos DB connection string. Obtain the value from the **Keys** page in the Cosmos DB account in the Azure portal; either the primary or secondary connection string can be used.\n    * The `Host` section configures the port and CORS settings for the local Functions host.\n\n1. Save the file.\n\n    ![](media/update-local-settings.png)\n\n---\n\n## Create an Azure Function to retrieve flight prices\n\n### GetFlights function\n\n#### Create the function\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Functions: Create Function** command.\n\n1. When prompted, provide the following information.\n\n    | Name | Value |\n    |---|---|\n    | Function app folder | select the main project folder |\n    | Template | HTTP Trigger |\n    | Name | GetFlights |\n    | Authorization level | Anonymous |\n    \n    A folder named **GetFlights** is created that contains the new function. A JavaScript Azure Function consists of two files: **function.json** and **index.js**.\n\n1. Open **GetFlights/function.json** to configure bindings for the function. Modify the content of the file to the following.\n    ```json\n    {\n      \"disabled\": false,\n      \"bindings\": [\n        {\n          \"authLevel\": \"anonymous\",\n          \"type\": \"httpTrigger\",\n          \"direction\": \"in\",\n          \"name\": \"req\"\n        },\n        {\n          \"type\": \"http\",\n          \"direction\": \"out\",\n          \"name\": \"res\"\n        },\n        {\n          \"type\": \"cosmosDB\",\n          \"name\": \"flights\",\n          \"ConnectionStringSetting\": \"AzureCosmosDBConnectionString\",\n          \"databaseName\": \"flightsdb\",\n          \"collectionName\": \"flights\",\n          \"direction\": \"in\"\n        }\n      ]\n    }\n    ```\n    This adds a Cosmos DB input binding that retrieves documents from a collection named `flights` from a database named `flightsdb`. `AzureCosmosDBConnectionString` is the name of the application setting that you configured earlier that contains the connection string to Cosmos DB.\n\n1. Save the file.\n\n1. Open **GetFlights/index.js** to view the body of the function. Modify the content of the file to the following.\n    ```javascript\n    module.exports = async function (context, req, flights) {\n      context.res.body = flights;\n    };\n    ```\n    Using the Cosmos DB input binding that you configured, Azure Functions retrieves all the documents in the specified Cosmos DB collection and passes them to the function in the `flights` argument as an array of objects. This function simply returns them directly as the HTTP response body. If you had any business logic that needs to run before returning the results, you can add them to the function.\n\n1. Save the file.\n\n\n#### (Optional) Test the function\n\n1. To run the function app locally, press **F5** in VS Code. If this is the first time, the Azure Functions host will start in the VS Code integrated terminal.\n\n1. When the functions runtime is successfully started, the terminal output will display a URL for the local **GetFlights** endpoint (by default, it is `http://localhost:7071/api/GetFlights`).\n\n1. Use Postman or your browser to issue a GET request to `http://localhost:7071/api/GetFlights`. It should return the document(s) you created earlier.\n    \u003e Note that Azure Functions automatically negotiates the response content type based on request headers. Some browsers are configured to receive responses in XML instead of JSON.\n\n1. Click the **Disconnect** button to stop the function host and stop debugging.\n\n\n## Create and run the frontend single page application\n\nThe flight application's UI is a simple single page application (SPA) created with Vue JavaScript framework. It will be hosted separately from the function app. Locally, you will run the web interface using the Live Server VS Code extension.\n\n1. In VS Code, create a new folder named **content** at the root of the main project folder.\n\n1. In the **content** folder, create a new file named **index.html**.\n\n1. Copy and paste the content of **[index.html](https://raw.githubusercontent.com/anthonychu/functions-serverless-realtime-tutorial/master/assets/index.html)**.\n\n1. Save the file.\n\n1. Press **F5** to run the function app locally and attach a debugger.\n\n1. Run the app using http-server that you installed earlier.\n    1. In a terminal, change into the **content** folder containing **index.html**.\n    1. Run `http-server`. The server should start and binds to **http://localhost:8080** by default.\n\n    \u003e If you are using a different web server or http-server uses a different port, you may need to update your `CORS` entry in **local.settings.json** and restart the function app.\n\n1. Open a browser and navigate to **http://localhost:8080/**. The app should appear and populated with the correct data from Cosmos DB.\n\n    ![](media/app-screenshot-1.png)\n\nNext, you will integrate Azure SignalR Service into your application to allow any changes in data to appear in real-time.\n\n\n---\n\n## Display updates in real-time with Azure SignalR Service\n\nAzure SignalR Service provides real-time messaging capabilities to supported clients, including web browsers. You will use Azure Functions to integrate with SignalR Service to broadcast database updates in real-time to connected browsers.\n\n\n### SignalR negotiate function\n\nThe single page application uses the SignalR client SDK to connect to SignalR Service. The SDK needs to retrieve the connection information required to connect to the service. You will create an HTTP endpoint to return this information using an Azure Function. By convention, this endpoint must be called **negotiate**.\n\n#### Create the function\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Functions: Create Function** command.\n\n1. When prompted, provide the following information.\n\n    | Name | Value |\n    |---|---|\n    | Function app folder | select the main project folder |\n    | Template | HTTP Trigger |\n    | Name | negotiate |\n    | Authorization level | Anonymous |\n    \n    A folder named **negotiate** is created that contains the new function.\n\n1. Open **negotiate/function.json** to configure bindings for the function. Modify the content of the file to the following. This adds an input binding that generates valid credentials for a client to connect to an Azure SignalR Service hub named `flights`.\n    ```json\n    {\n        \"disabled\": false,\n        \"bindings\": [\n            {\n                \"authLevel\": \"anonymous\",\n                \"type\": \"httpTrigger\",\n                \"direction\": \"in\",\n                \"name\": \"req\"\n            },\n            {\n                \"type\": \"http\",\n                \"direction\": \"out\",\n                \"name\": \"res\"\n            },\n            {\n                \"type\": \"signalRConnectionInfo\",\n                \"name\": \"connectionInfo\",\n                \"hubName\": \"flights\",\n                \"direction\": \"in\"\n            }\n        ]\n    }\n    ```\n\n1. Open **negotiate/index.js** to view the body of the function. Modify the content of the file to the following.\n\n    ```javascript\n    module.exports = async function (context, req, connectionInfo) {\n      context.res.body = connectionInfo;\n    };\n    ```\n\n    This function takes the SignalR connection information from the input binding and returns it to the client in the HTTP response body.\n\n\n#### (Optional) Test the function\n\n1. To run the function app locally, press **F5** in VS Code. If this is the first time, the Azure Functions host will start in the VS Code integrated terminal.\n\n1. When the functions runtime is successfully started, the terminal output will display URLs for the local endpoints, including **negotiate** (by default, it is `http://localhost:7071/api/negotiate`).\n\n1. Use Postman or your browser to issue a GET request to `http://localhost:7071/api/negotiate`. It should return an endpoint and an access token that the SignalR JavaScript SDK will use to connect to SignalR Service.\n    \u003e Note that Azure Functions automatically negotiates the response content type based on request headers. Some browsers are configured to receive responses in XML instead of JSON.\n\n1. Press the **Disconnect** button to disconnect the debugger from the function host.\n\n\n### Broadcast Cosmos DB changes to all clients\n\n#### Create the CosmosTrigger function\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Functions: Create Function** command.\n\n1. When prompted, provide the following information.\n\n    | Name | Value |\n    |---|---|\n    | Function app folder | select the main project folder |\n    | Template | Azure Cosmos DB Trigger |\n    | Name | CosmosTrigger |\n    | App setting for your account Cosmos DB account | AzureCosmosDBConnectionString |\n    | Database name | flightsdb |\n    | Collection name | flights |\n    | Collection name for leases | leases |\n    | Create lease collection of not exists | true |\n    \n    A folder named **CosmosTrigger** is created that contains the new function.\n\n1. Open **CosmosTrigger/function.json** to configure bindings for the function. Modify the content of the file to the following. This adds an input binding that generates valid credentials for a client to connect to an Azure SignalR Service hub named `flights`.\n    ```json\n    {\n      \"disabled\": false,\n      \"bindings\": [\n        {\n          \"type\": \"cosmosDBTrigger\",\n          \"name\": \"documents\",\n          \"direction\": \"in\",\n          \"databaseName\": \"flightsdb\",\n          \"collectionName\": \"flights\",\n          \"createLeaseCollectionIfNotExists\": true,\n          \"ConnectionStringSetting\": \"AzureCosmosDBConnectionString\",\n          \"feedPollDelay\": 1000\n        },\n        {\n          \"type\": \"signalR\",\n          \"name\": \"signalRMessages\",\n          \"hubName\": \"flights\",\n          \"direction\": \"out\"\n        }\n      ]\n    }\n    ```\n\n    This adds the a SignalR output binding to the function that will be used to send updates to SignalR Service. It also increases the frequency that the function app polls for changes in Cosmos DB from the default 5 seconds to 1 second (1000ms).\n\n1. Open **CosmosTrigger/index.js** to view the body of the function. Modify the content of the file to the following.\n\n    ```javascript\n    module.exports = async function (context, documents) {\n      context.bindings.signalRMessages =\n        documents.map(flight =\u003e ({\n          target: 'flightUpdated',\n          arguments: [ flight ]\n        }));\n    };\n    ```\n\n    This function is triggered whenever one or more documents are updated in the Cosmos DB collection. Each document contains a flight whose data was updated. The function uses the SignalR output binding to raise an event named **flightUpdated** on each client that is connected to SignalR Service, passing the updated flight as the argument.\n\n\n#### Test the app\n\n1. Press **F5** to run the function app locally and attach a debugger.\n\n1. If you shut down http-server that you started earlier, restart it in the **content** directory.\n\n1. Browse to **http://localhost:8080/**. The app appears with the current flight prices.\n\n1. Go to the Azure portal and navigate to the Data Explorer of the Cosmos DB account. Locate the document containing the flight information that is currently displayed in the app.\n\n1. Modify the price of the flight in the Data Explorer and save it. The new price should change in the browser without refreshing the app.\n\n\n---\n\n## Deploy to Azure\n\nYou have been running the function app and the frontend locally. You will now deploy them to Azure.\n\n\n### Log into Azure with VS Code\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure: Sign in** command.\n\n1. Follow the instructions to complete the sign in process in your browser.\n\n\n### Deploy the function app\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Functions: Deploy to Function App** command.\n\n1. When prompted, provide the following information.\n\n    | Name | Value |\n    |---|---|\n    | Folder to deploy | Select the main project folder |\n    | Subscription | Select your subscription |\n    | Function app | Select **Create New Function App** |\n    | Function app name | Enter a unique name |\n    | Resource group | Select the same resource group as your other resources in this tutorial |\n    | Storage account | Select the account you created earlier |\n    \n    A new function app is created in Azure and the deployment begins. The Azure Functions VS Code extension will first create the Azure resources; then it will deploy the function app. Wait for deployment to complete.\n\n\n### Upload function app local settings\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Functions: Upload local settings** command.\n\n1. When prompted, provide the following information.\n\n    | Name | Value |\n    |---|---|\n    | Local settings file | local.settings.json |\n    | Subscription | Select your subscription |\n    | Function app | Select the previously deployed function app |\n    | Function app name | Enter a unique name |\n\nLocal settings are uploaded to the function app in Azure. If prompted to overwrite existing settings, select **Yes to all**.\n\n\n\n### Configure static websites in Storage\n\nThe Storage account that you're using for this tutorial is the perfect place to host the frontend in Azure. First, you need to configure it to host a static website.\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Storage: Configure static website** command.\n\n1. Select your subscription and storage account. The browser will open directly to the page for configuring this setting.\n\n1. Select **Enabled**.\n\n1. Enter `index.html` as the **Index document name**.\n\n1. Click **Save**.\n\n1. The static websites **primary endpoint** appears on the screen. Note this value as it will be required to configure cross origin resource sharing (CORS) in the Azure Function app.\n\n\n### Enable function app cross origin resource sharing (CORS)\n\nAlthough there is a CORS setting in **local.settings.json**, it is not propagated to the function app in Azure. You need to set it separately.\n\n#### Add CORS origin\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Functions: Open in portal** command.\n\n1. Select the subscription and function app name to open the function app in the Azure portal.\n\n1. Under the **Platform features** tab, select **CORS**.\n\n1. Add an entry with the static website **primary endpoint** as the value (remove the trailing `/`).\n\n    ![](media/cors-settings.png)\n\n1. Click **Save** to persist the CORS settings.\n\n#### Enable CORS credentials support\n\nIn order for the SignalR JavaScript SDK to function and to add authentication to the application later in the tutorial, support for credentials in CORS must be enabled.\n\nCurrently, this feature can only be enabled using the Azure command line interface (CLI) or REST APIs. You will execute a command in Azure Cloud Shell to enable this feature. This tutorial will be updated once the portal supports this feature.\n\n1. In the Azure portal, click the **Cloud Shell** button to open a Cloud Shell terminal in the browser.\n\n1. Execute the following command, replacing `\u003c\u003e` with valid values based on resources you have created.\n\n    ```\n    az resource update --resource-group \u003cresource_group_name\u003e --parent sites/\u003cfunction_app_name\u003e --name web --namespace Microsoft.Web --resource-type config --set properties.cors.supportCredentials=true --api-version 2015-06-01\n    ```\n\n    ![](media/cloud-shell.png)\n\n1. Once completed, CORS credentials support is enabled in the function app.\n\n\u003e Note: There is currently a bug in the Azure portal, where updating the CORS origins like you did in the previous step will disable CORS credentials support. Rerun the above command if this happens. A fix is rolling out in late January.\n\n\n### Update function app URL in the frontend\n\n1. In the Azure portal, navigate to the function app's overview page.\n\n1. Copy the function app's URL.\n\n    ![](media/function-app-url.png)\n\n1. In VS Code, open **index.html** and replace the value of `apiBaseUrl` with the function app's URL.\n\n1. Save the file.\n\n    ![](media/update-url.png)\n\n\n### Deploy frontend to Storage\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Storage: Deploy to static website** command.\n\n1. Select the subscription and Storage account.\n\n1. When prompted for a folder, select **browse** and choose the **content** folder containing index.html.\n\n1. A notification should appear that the upload was successful. Click the button to open the app in a browser.\n\n1. Change the document to Cosmos DB or add a new document (use the same schema as the first document), the update should appear in the browser.\n\n1. Congratulations, you've deployed a serverless real-time web application to Azure!\n\n\n---\n\n## Add Authentication\n\nAzure Functions has built-in authentication, supporting popular providers such as Facebook, Twitter, Microsoft Account, Google, and Azure Active Directory. You will now add authentication to your application and allow authenticated users to update or create flights.\n\n### Create the UpdateFlight function\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Functions: Create Function** command.\n\n1. When prompted, provide the following information.\n\n    | Name | Value |\n    |---|---|\n    | Function app folder | select the main project folder |\n    | Template | HTTP Trigger |\n    | Name | UpdateFlight |\n    | Authorization level | Anonymous |\n    \n    A folder named **UpdateFlight** is created that contains the new function.\n\n1. Open **UpdateFlight/function.json** to configure bindings for the function. Modify the content of the file to the following. This restricts the function to only POST requests, and adds a Cosmos DB output binding that takes care of updating and creating documents in the specified Cosmos DB collection.\n    ```json\n    {\n      \"disabled\": false,\n      \"bindings\": [\n        {\n          \"authLevel\": \"anonymous\",\n          \"type\": \"httpTrigger\",\n          \"direction\": \"in\",\n          \"name\": \"req\",\n          \"methods\": [ \"post\" ]\n        },\n        {\n          \"type\": \"http\",\n          \"direction\": \"out\",\n          \"name\": \"res\"\n        },\n        {\n          \"name\": \"flight\",\n          \"type\": \"cosmosDB\",\n          \"databaseName\": \"flightsdb\",\n          \"collectionName\": \"flights\",\n          \"createIfNotExists\": true,\n          \"connectionStringSetting\": \"AzureCosmosDBConnectionString\",\n          \"direction\": \"out\"\n        }\n      ]\n    }\n    ```\n\n1. Open **UpdateFlight/index.js** to view the body of the function. Modify the content of the file to the following.\n\n    ```javascript\n    module.exports = async function (context, req) {\n        const isAuthEnabled = process.env.WEBSITE_AUTH_ENABLED;\n        const username = req.headers['x-ms-client-principal-name'];\n        if (!isAuthEnabled || !username) {\n            context.res = { status: 403, statusText: 'Forbidden' };\n            return;\n        }\n    \n        const flight = req.body;\n        flight.username = username;\n        context.bindings.flight = flight;\n    };\n    ```\n\n    This function first ensures that authentication is enabled and that the user is authenticated. Then it takes the request body, adds the username, and saves it to Cosmos DB using the output binding named `flight`.\n\n    \u003e Note that local testing of functions authentication is coming soon. Until then, you will test this function in Azure.\n\n\n### Deploy the updated function\n\n1. Open the VS Code command palette (`Ctrl-Shift-P`, macOS: `Cmd-Shift-P`).\n\n1. Search for and select the **Azure Functions: Deploy to Function App** command.\n\n1. When prompted, select the subscription and function app that you deployed earlier.\n    \n1. Wait for the app to finish deployment.\n\n\n### Enable authentication in the function app\n\n1. In the Azure portal, open your function app.\n\n1. Click on the **Platform Features** tab. Select **Authentication/Authorization**.\n\n1. Select **On** to turn on App Service Authentication.\n\n1. Under **Action to take when request is not authenticated**, select **Allow Anonymous requests (no action)**. This enables authentication, but does not require a request to be authenticated to call a function.\n\n1. Follow the instructions for the authentication provider you'd like to use.\n    - [Facebook](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-facebook)\n    - [Twitter](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-twitter)\n    - [Google](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-google)\n    - [Microsoft Account](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-microsoft)\n    - [Azure Active Directory](https://docs.microsoft.com/azure/app-service/configure-authentication-provider-aad)\n\n1. Add the Storage static website **primary endpoint** to the list of allowed external redirect URLs.\n    ![](media/configure-aad-2.png)\n\n1. Click **Save** and authentication will be configured.\n\n\n### Update the application to use authentication\n\n1. In VS Code, open **content/index.html**.\n\n1. Change the `authProvider` constant to the value corresponding to the authentication provider you selected:\n    - `facebook`\n    - `twitter`\n    - `google`\n    - `microsoftaccount`\n    - `aad` (Azure Active Directory)\n\n1. Save the file.\n\n1. Search for and select the **Azure Storage: Deploy to static website** command.\n\n1. Select the subscription and Storage account.\n\n1. When prompted for a folder, select **browse** and choose the **content** folder containing index.html.\n\n1. A notification should appear that the upload was successful. Click the button to open the app in a browser.\n\n1. The application should now display a login link. After you log in, you'll be able to update prices and add new flights. Changes you make will be reflected in all browsers that have the app open, in real-time.\n\n\n## Summary\n\nCongratulations! You have successfully built a serverless web app that is hosted on Azure Storage static websites and uses a backend running on Azure Functions. The application stores data in Azure Cosmos DB, and uses the Cosmos DB change feed in combination with Azure SignalR Service to update data in browsers via WebSocket. Finally, you added authentication to the app.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanthonychu%2Ffunctions-serverless-realtime-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanthonychu%2Ffunctions-serverless-realtime-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanthonychu%2Ffunctions-serverless-realtime-tutorial/lists"}