Quickstart: Use JavaScript to create an App showing GitHub star count with Azure Functions and SignalR Service

In this article, you'll use Azure SignalR Service, Azure Functions, and JavaScript to build a serverless application to broadcast messages to clients.

Note

You can get all code mentioned in the article from GitHub.

Prerequisites

The examples should work with other versions of Node.js, for more information, see Azure Functions runtime versions documentation.

This quickstart can be run on macOS, Windows, or Linux.

Create an Azure SignalR Service instance

In this section, you'll create a basic Azure SignalR instance to use for your app. The following steps use the Azure portal to create a new instance, but you can also use the Azure CLI. For more information, see the az signalr create command in the Azure SignalR Service CLI Reference.

  1. Sign in to the Azure portal.
  2. In the upper-left side of the page, select + Create a resource.
  3. On the Create a resource page, in the Search services and marketplace text box, enter signalr and then select SignalR Service from the list.
  4. On the SignalR Service page, select Create.
  5. On the Basics tab, you'll enter the essential information for your new SignalR Service instance. Enter the following values:
Field Suggested Value Description
Subscription Choose your subscription Select the subscription you want to use to create a new SignalR Service instance.
Resource group Create a resource group named SignalRTestResources Select or create a resource group for your SignalR resource. It's useful to create a new resource group for this tutorial instead of using an existing resource group. To free resources after completing the tutorial, delete the resource group.

Deleting a resource group also deletes all of the resources that belong to the group. This action can't be undone. Before you delete a resource group, make certain that it doesn't contain resources you want to keep.

For more information, see Using resource groups to manage your Azure resources.
Resource name testsignalr Enter a unique resource name to use for the SignalR resource. If testsignalr has already been used in your region, add a digit or character until the name is unique.

The name must be a string of 1 to 63 characters and contain only numbers, letters, and the hyphen (-) character. The name can't start or end with the hyphen character, and consecutive hyphen characters aren't valid.
Region Choose your region Select the appropriate region for your new SignalR Service instance.

Azure SignalR Service isn't currently available in all regions. For more information, see Azure SignalR Service region availability
Pricing tier Select Change and then choose Free (Dev/Test Only). Choose Select to confirm your choice of pricing tier. Azure SignalR Service has three pricing tiers: Free, Standard, and Premium. Tutorials use the Free tier, unless noted otherwise in the prerequisites.

For more information about the functionality differences between tiers and pricing, see Azure SignalR Service pricing
Service mode Choose the appropriate service mode for this tutorial Use Default for ASP.NET. Use Serverless for Azure Functions or REST API.

Classic mode isn't used in the Azure SignalR tutorials.

For more information, see Service mode in Azure SignalR Service.

You don't need to change the settings on the Networking and Tags tabs for the SignalR tutorials.

  1. Select the Review + create button at the bottom of the Basics tab.
  2. On the Review + create tab, review the values and then select Create. It will take a few moments for deployment to complete.
  3. When the deployment is complete, select the Go to resource button.
  4. On the SignalR resource screen, select Keys from the menu on the left, under Settings.
  5. Copy the Connection string for the primary key. You'll need this connection string to configure your app later in this tutorial.

Setup and run the Azure Function locally

Make sure you have Azure Functions Core Tools installed.

  1. Using the command line, create an empty directory and then change to it. Initialize a new project:

    # Initialize a function project
    func init --worker-runtime javascript
    
  2. After you initialize a project, you need to create functions. In this sample, we'll create three functions:

    1. Run the following command to create a index function, which will host a web page for clients.

      func new -n index -t HttpTrigger
      

      Open index/function.json and copy the following json code:

      {
        "bindings": [
          {
            "authLevel": "anonymous",
            "type": "httpTrigger",
            "direction": "in",
            "name": "req",
            "methods": [
              "get",
              "post"
            ]
          },
          {
            "type": "http",
            "direction": "out",
            "name": "res"
          }
        ]
      }
      

      Open index/index.js and copy the following code:

      var fs = require('fs').promises
      
      module.exports = async function (context, req) {
          const path = context.executionContext.functionDirectory + '/../content/index.html'
          try {
              var data = await fs.readFile(path);
              context.res = {
                  headers: {
                      'Content-Type': 'text/html'
                  },
                  body: data
              }
              context.done()
          } catch (error) {
              context.log.error(err);
              context.done(err);
          }
      }
      
    2. Create a negotiate function for clients to get an access token.

      func new -n negotiate -t SignalRNegotiateHTTPTrigger
      

      Open negotiate/function.json and copy the following json code:

      {
        "disabled": false,
        "bindings": [
          {
            "authLevel": "anonymous",
            "type": "httpTrigger",
            "direction": "in",
            "methods": [
              "post"
            ],
            "name": "req",
            "route": "negotiate"
          },
          {
            "type": "http",
            "direction": "out",
            "name": "res"
          },
          {
            "type": "signalRConnectionInfo",
            "name": "connectionInfo",
            "hubName": "serverless",
            "connectionStringSetting": "AzureSignalRConnectionString",
            "direction": "in"
          }
        ]
      }
      
    3. Create a broadcast function to broadcast messages to all clients. In the sample, we use a time trigger to broadcast messages periodically.

      func new -n broadcast -t TimerTrigger
      

      Open broadcast/function.json and copy the following code:

      {
        "bindings": [
          {
            "name": "myTimer",
            "type": "timerTrigger",
            "direction": "in",
            "schedule": "*/5 * * * * *"
          },
          {
            "type": "signalR",
            "name": "signalRMessages",
            "hubName": "serverless",
            "connectionStringSetting": "AzureSignalRConnectionString",
            "direction": "out"
          }
        ]
      }
      

      Open broadcast/index.js and copy the following code:

      var https = require('https');
      
      var etag = '';
      var star = 0;
      
      module.exports = function (context) {
          var req = https.request("https://api.github.com/repos/azure/azure-signalr", {
              method: 'GET',
              headers: {'User-Agent': 'serverless', 'If-None-Match': etag}
          }, res => {
              if (res.headers['etag']) {
                  etag = res.headers['etag']
              }
      
              var body = "";
      
              res.on('data', data => {
                  body += data;
              });
              res.on("end", () => {
                  if (res.statusCode === 200) {
                      var jbody = JSON.parse(body);
                      star = jbody['stargazers_count'];
                  }
      
                  context.bindings.signalRMessages = [{
                      "target": "newMessage",
                      "arguments": [ `Current star count of https://github.com/Azure/azure-signalr is: ${star}` ]
                  }]
                  context.done();
              });
          }).on("error", (error) => {
              context.log(error);
              context.res = {
                status: 500,
                body: error
              };
              context.done();
          });
          req.end();
      }
      
  3. The client interface of this sample is a web page. We read HTML content from content/index.html in the index function, create a new file named index.html in the content directory under your project root folder. Copy the following code:

    <html>
    
    <body>
      <h1>Azure SignalR Serverless Sample</h1>
      <div id="messages"></div>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.min.js"></script>
      <script>
        let messages = document.querySelector('#messages');
        const apiBaseUrl = window.location.origin;
        const connection = new signalR.HubConnectionBuilder()
            .withUrl(apiBaseUrl + '/api')
            .configureLogging(signalR.LogLevel.Information)
            .build();
          connection.on('newMessage', (message) => {
            document.getElementById("messages").innerHTML = message;
          });
    
          connection.start()
            .catch(console.error);
      </script>
    </body>
    
    </html>
    
  4. You're almost done now. The last step is to set a connection string of the SignalR Service to Azure Function settings.

    1. In the Azure portal, find the SignalR instance you deployed earlier by typing its name in the Search box. Select the instance to open it.

      Search for the SignalR Service instance

    2. Select Keys to view the connection strings for the SignalR Service instance.

      Screenshot that highlights the primary connection string.

    3. Copy the primary connection string. And execute the command below.

      func settings add AzureSignalRConnectionString "<signalr-connection-string>"
      
  5. Run the Azure function in local host:

    func start
    

    After Azure Function running locally. Use your browser to visit http://localhost:7071/api/index and you can see the current star count. And if you star or "unstar" in GitHub, you'll see the star count refreshing every few seconds.

    Note

    SignalR binding needs Azure Storage, but you can use local storage emulator when the function is running locally. If you got an error like There was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid. You need to download and enable Storage Emulator

Having issues? Try the troubleshooting guide or let us know

Clean up resources

If you're not going to continue to use this app, delete all resources created by this quickstart with the following steps so you don't incur any charges:

  1. In the Azure portal, select Resource groups on the far left, and then select the resource group you created. Alternatively, you may use the search box to find the resource group by its name.

  2. In the window that opens, select the resource group, and then click Delete resource group.

  3. In the new window, type the name of the resource group to delete, and then click Delete.

Next steps

In this quickstart, you built and ran a real-time serverless application in localhost. Next, learn more about how to bi-directional communicating between clients and Azure Function with SignalR Service.