June 2018

Volume 33 Number 6

[Data Points]

Replacing a Bulky API with Azure Functions

By Julie Lerman | June 2018

Code download available at msdn.com/magazine/0618magcode.

Back in 2015 and 2016, I wrote a few columns about a Node.js Web API that interacted with Azure DocumentDB. There was a lot involved. Even though I took advantage of the Node.js SDK designed for DocumentDB, I still had to write a lot of logic. There was logic for building up objects that represented the DocumentDB account, the database and the collections. There was code to create queries and to execute them—layers of asynchronous calls. But I was able to write a nice little API that allowed my application to create, query and update data in the database.

In more recent columns, I’ve worked with Azure Functions, Microsoft’s serverless APIs that live in Azure and integrate seamlessly with other Azure technologies. One of those integrations is with Azure Cosmos DB, the data storage into which Azure DocumentDB evolved.

Having written a number of Azure Functions, integrating them with Cosmos DB to read and write data, I looked back at my older Node.js APIs and realized I could eliminate about 98 percent of the code by converting them into Azure Functions. That’s because most of the code I had written was to interact with the database, but now Azure Functions take care of all of that work. With nothing more than a configuration to identify the connection string—whether the data is coming from the database or going into it—and the relevant query, the built-in features of the function will take care of the rest.

Using Visual Studio Code and Extensions

In the earlier Azure Functions columns, I worked directly in the Azure portal. But it’s also possible to use the Azure Functions Core Tools to develop on your computer and then deploy to Azure. The first version of the tools (version 1) runs only on Windows, with .NET 4.7.1 or higher, and there’s a Visual Studio 2017 extension for working with those tools.

In contrast, version 2 of the Azure Functions Core Tools runs on .NET Core and is cross-platform, and a Visual Studio Code extension lets you work with it handily (bit.ly/2H7VmxH). That’s the version I’ll be working with in this article. Note that both the tools and the extension are in preview.

Working with this extension has a few setup requirements, which you’ll find in the Read Me for the Visual Studio Code extension. And it assumes you’ve already installed Visual Studio Code and its prerequisites on your system, which could be Windows, macOS or Linux.

The extension helps you easily create new Azure Function App folders to contain Azure Functions, create the functions (with a variety of templates to choose from), run and debug them locally, and deploy them to Azure. I’ve been really impressed because it takes away the hard work and all you have to do is focus on your code—which is the promise of serverless computing.

In addition to the Azure Functions extension, I also installed the Azure Cosmos DB extension for Visual Studio Code (bit.ly/2HkPfDE). I’m using that to look at the collections and documents of my existing databases, but you can also use the extension to create new Cosmos DB accounts, databases and collections, as well as retrieve and update documents and create new documents. I’ve put in a suggestion to be able to import documents given pre-existing JSON files and hope to see that in there someday.

Critical to using both of these extensions is the ability to sign into your Azure account from Visual Studio Code, so I’ve also installed the Azure Account extension (bit.ly/2k1phdp).

Each of these three extensions have handy walk-throughs on the pages I’ve linked to, which will help you get started using them. I’ll do a light walk-through here for the purpose of showing you how much easier it is to create the Azure Function counterparts of my Node.js Web API than it was to build all of the code and dependencies I relied on for the Node.js solution. I will, however, still use JavaScript as the language for my functions. JavaScript and Node.js support is built into Visual Studio Code.

Creating the Azure Functions Project

After installing the three extensions and their dependencies, it was time to recreate my API. I started by creating a new folder on my computer, named NinjaFunctions, then opening it in Visual Studio Code. If you’re following along, begin by using the Azure Functions extension to turn the folder into an Azure Functions folder. You can do this by clicking the Create New Project icon (which looks like a folder), on the toolbar of the Azure Functions pane. Then follow the prompts to select the already opened NinjaFunctions folder and the language. I’m choosing JavaScript. The extension will then add some files needed for the functions into your folder, and initialize a Git repository. Figure 1 shows the IDE with the results of this process in the Azure Functions output window, as well as the files (.vscode, .gitignore, host.json and local.settings.json) it added. You can also see the Azure Functions pane listing all of my cloud-based Azure Function Apps and, below that, my Cosmos DB databases, thanks to that extension.

Figure 1 Visual Studio Code After Creating the New Azure Functions Project

Creating an Azure Function in the Project

With the project set up, it’s time to create the first function. This function will import JSON files into my Cosmos DB database. Note that I’ve already created the new database account (lermandatapoints) but I haven’t yet created a database or a collection. I’ll do that using the Azure Cosmos DB extension. In the extension pane, right-click on the Cosmos DB account where you want to create the database and choose Create Database from the menu. Type in the new name when prompted (mine, naturally, is Ninjas) and this database will be created in your Azure account using default settings. Feel free to tweak those settings in the portal if necessary. Finally, create a collection in the database by right-clicking the new database, choosing Create Collection and providing its name. I’ll be boring and call my collection Ninjas, as well. You can leave the partition key blank for this little demo.

The goal of the first function is to read an existing document supplied in JSON format and add it to the new collection.  If you’ve read my recent Azure Functions articles in this column, you may recall that one is called “Creating Azure Functions That Can Read from Cosmos DB with Almost No Code” (msdn.com/magazine/mt829268). In this case, I’ll be creating a function that can write to Cosmos DB with almost no code.

I won’t be building a front end. Instead, I’ll be using the Postman application to construct calls to my APIs and pass the JSON document in as a message body. You can do the same with Fiddler, as well.

Back on the Azure Functions extension pane, click the Create Function icon to create a new function in the project folder. I want this function to respond to HTTP requests, so select HTTP trigger and then provide a name. Mine is AddNinja­Document. Following the prompts, make the function anonymous so it’s easier to test without having to provide credentials.

In response to this action, the extension creates a new folder with three files:

• function.json, which contains the default configuration for the function

• index.js file for the logic

• a sample data file

Configuring the Function

Like the function created in my January 2018 column, “Creating Azure Functions to Interact with Cosmos DB” (msdn.com/magazine/mt814991), this function will output data to a Cosmos DB database. In the earlier article, I used the portal to configure this integration and the portal wrote my choices into a function.json file. This time, I’ll define the configuration manually in function.json. Open the file and you’ll see two integrations already defined, based on the fact that the HTTP trigger template was used. After the second integration, add a comma and then copy in this cosmosDB configuration, which specifies the name of the document to send to the database, the type of integration (cosmosDB), the database and collection names, the connection setting, and the direction of the integration (out to the database):

{
  "name": "outputDocument",
  "type": "cosmosDB",
  "databaseName": "Ninjas",
  "collectionName": "Ninjas",
  "createIfNotExists": true,
  "connectionStringSetting": "mydbconnection",    
  "direction": "out"
}

I can define the connection string in the local.settings.json file so I don’t have to hard code it into the function.json file. Local.settings.json is the local representation of the app.settings.json file that will live in the portal and contain your application secrets.

So, here, I’m just saying that the connection string can be found in a setting called mydbconnection.

The setting goes in the Values section of local.settings.json. You can copy the connection string by right-clicking the Cosmos DB account in the Cosmos DB extension pane and then pasting it into the json file. The string will start with:

"mydbconnection":
"AccountEndpoint=https://yourdb.documents.azure.com/

In an upcoming enhancement to the Azure Function Core Tools, the presence of the cosmosDB type in the function.json file will trigger the extension to automatically install a package with the logic needed to run and debug your project locally. At this time, though, you’ll need to install this package manually. Let’s do that now.

In the terminal window, be sure you’re pointed to the root folder, Ninja­Functions, and enter the following Azure Functions CLI command:

func extensions install -p Microsoft.Azure.WebJobs.Extensions.CosmosDb -v 3.0.0-beta7

Note that I’m installing the beta version that’s current as I’m writing this article. You can check its NuGet page for the latest version if you do have to install it manually (bit.ly/2EyLNCw). This will create a new folder called functions-extensions in your project (see Figure 2). The folder contains a .NET Standard 2.0 project, which is driven by the project file, extensions.csproj. The csproj code listing is in Figure 3.

Figure 2 The New Functions-­Extensions Folder to House the Cosmos DB Extension

Figure 3 The extensions.csproj Folder with References to the Cosmos DB Extension

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
      <WarningsAsErrors></WarningsAsErrors>
      <DefaultItemExcludes>**</DefaultItemExcludes>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDb"                       Version="3.0.0-beta7" />
    <PackageReference       Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator"       Version="1.0.0-beta2" />
  </ItemGroup>
</Project>

Adding the Tiny Bit of Code

Let’s get back to the AddNinjaDocuments function. The function.json file is all set, so the next step is to complete the index.js file, which is where the function’s logic lives. You can delete all of the default sample code. All you really need for the function is code to bind the incoming JSON to the function’s output; in other words, what gets sent to the Cosmos DB collection:

module.exports = function (context, req) {
  context.bindings.outputDocument=req.body;
  context.done();
};

But it’s helpful to have a little bit of debugging info. So, rather than the pure minimalist version, replace the entire contents of the default sample code with the following:

module.exports = function (context, req) {   
  context.log('HTTP request received.');
  try {
    context.bindings.outputDocument = req.body;
  }
  catch (error) {
    context.log(error);
  }
  context.bindings.res = { status: 201, body: "Insert succeeded." };
  context.done();
};

The JavaScript code is quite different from the C# function code I wrote in the previous articles. You can learn about the structure of JavaScript in Azure Functions at bit.ly/2GQ9eJt.

The context being passed in to the function is used by the runtime to pass data in and out of the function. I named the Cosmos DB binding “outputDocument” in the function.json configuration. Now I’m setting that binding to whatever body is encapsulated in the incoming HTTP request. The template created a binding named res for the HTTP response, which I’m using to relay the success of the function. The context.done method signals to the runtime that the function is complete.

Running the Function in Visual Studio Code

So, that’s all there is to the function! Everything else is taken care of by the application settings, the function configuration and Azure Functions APIs. You can go ahead and run the function in Visual Studio Code. While it’s absolutely possible to debug, set breakpoints and explore variables, let’s just run the function app, which you can do in the terminal with the command:

func start

This will display the brightly colored Azure Functions logo in the terminal window and then output some processing info. At the end of all this output, you’ll see the URL where the function is running. If there are multiple functions in your project, the URLs will be listed separately for each. In Postman or Fiddler, build a POST request using this URL. In the body section you can paste in the JSON listed in Figure 4 and then send the request. Figure 5 shows my Postman UI, with the request URL and body displayed, along with the response.

Figure 4 JSON Code for a Document To Be Inserted into the Database

 

{
    "Name": "Kacy Catanzaro",
    "ServedInOniwaban": false,
    "Clan": "American Ninja Warriors",
    "Equipment": [
      {
        "EquipmentName": "Muscles",
        "EquipmentType": "Tool"
      },
      {
        "EquipmentName": "Spunk",
        "EquipmentType": "Tool"
      }
    ],
    "DateOfBirth": "1/14/1990"
  }

Figure 5 Creating a Request to Call the AddNinjaDocuments Function

Verifying the Insert

While the HTTP response in Figure 5 does say that all went well, it’s nice to actually see the data that was sent to the database in the cloud. And thanks to the Azure Cosmos DB extension, you can verify that directly in Visual Studio Code. First, let’s be sure that the function app stops running. In the terminal window, press CTRL+C to shut down the host. You may need to press CTRL+C a second time to get the prompt back in the terminal.

Now, in the Cosmos DB extension, expand the account, the database and the collection. You may need to refresh the view with the refresh icon on the extension’s pane. Within the collection, you can see the document that was just added. Select that to open it in the editor where you’ll see not just the data you added, but the metadata added by Azure Cosmos DB, as shown in Figure 6.

Figure 6 The New Document as Displayed by the Cosmos DB Extension

Next Steps

The download that accompanies this article also includes two more functions I created to replace the other methods from the original Node.js API. One is to return data filtered by a name part and the other to return data based on the id. With these, rather than having output binding to Cosmos DB, there’s an input binding that defines the database query using the SQL API. The HTTP response spits out the JSON representation of the query results.

Once you’ve tested and debugged your Azure Functions in Visual Studio Code, you can also use the extension to publish the functions to your Azure account. You can learn more about that from the extension’s ReadMe.

I recommend taking a look at the download from my original article, which is also in a GitHub repository at github.com/julielerman/AureliaDocDB. The API is in the models folder and, as you’ll see, there’s a lot more code involved with making read and write calls into the DocumentDB than for the Azure Functions, thanks to its integ­ration with Cosmos DB. I think in my coding future, I’ll always consider Azure Functions as the first line of defense when it’s time to write another Web API!


Julie Lerman is a Microsoft Regional Director, Microsoft MVP, software team coach and consultant who lives in the hills of Vermont. You can find her presenting on data access and other topics at user groups and conferences around the world. She blogs at the thedatafarm.com/blog and is the author of “Programming Entity Framework,” as well as a Code First and a DbContext edition, all from O’Reilly Media. Follow her on Twitter: @julielerman and see her Pluralsight courses at juliel.me/PS-Videos.