As announced at MongoDB World ‘17, MongoDB Atlas, the database-as-a-service provided by the creators of MongoDB, is now available on the three major public cloud providers: Amazon Web Services, Google Cloud Platform and Microsoft Azure. In this blog post, I’ll cover the integration of Microsoft Azure Functions with MongoDB Atlas from a developer standpoint.
What are Azure Functions? In a nutshell, Azure Functions are the core building block of Microsoft’s serverless technologies, similar to AWS Lambda and Google Cloud Functions. You can write your Azure Functions code in a variety of languages and execute it at scale without worrying about the underlying virtual machine and operating system.
That’s not very different from other cloud vendor offerings, but what seems to be unique about Azure Functions is Microsoft’s promise to open source the Azure Functions Runtime, which means that we could theoretically run Azure functions anywhere - on Azure, on private data centers or in other cloud providers. At the time of writing, we have yet to see whether Microsoft will deliver on that promise). To their credit, Microsoft already provides tools to run and debug Azure functions locally, as we’ll see below.
In this post I’ll introduce you to the process I recommend to create an Azure function with Visual Studio. I’ll also show how to leverage the .NET MongoDB driver to perform CRUD operations on a fully-managed MongoDB Atlas hosted on Azure.
Specifically, I will take you through the following steps:
- Set up your development environment
- Create an Azure function in Visual Studio
- Write MongoDB CRUD queries
- Connect the Azure function to MongoDB Atlas
- Test the Azure function locally
- Deploy the Azure function to Microsoft Azure
- Configure and test the Azure function running on Microsoft Azure
Set up your development environment
First, you should make sure you have Visual Studio 2017 version 15.3 (or higher) installed on your Windows machine (the Community Edition is enough, but the Professional and Enterprise Edition also work with this tutorial). At the time of this writing, Visual Studio 2017 version 15.3 is in Preview and can be installed from https://visualstudio.com/vs/preview (VS 2017 v15.3 is required to run the Azure Functions Tools for Visual Studio 2017)
When installing Visual Studio 2017, make sure you select the Azure development workload (as well as any other workload you wish to install).
If you already installed Visual Studio 2017, but did not install the Azure development workload, you can do so by going to Settings → Apps & features, find the Visual Studio 2017 app and select Modify.
At the time of writing, the Azure Functions Tools for Visual Studio 2017 must be installed as a Visual Studio extension. Please refer to Microsoft’s documentation for detailed installation instructions.
Create an Azure function in Visual Studio
Azure Functions offer a wide choice of programming languages, such as C#, F#, Node.js, Python, PHP and more. Given that C# is the language of choice of most Microsoft developers, this tutorial will focus on developing and deploying an Azure function using C#.
Open Visual Studio 2017 and select File → New → Project. Select the Azure Functions project type and give your project a name (for instance MongoDB.Tutorials.AzureFunctions).
Next, right-click on your project in the Solution Explorer and select Add → New item. Select the Azure Function item and give it a name such as CreateRestaurantFunction.cs (the file name doesn’t matter as much as the function name, as we’ll see below).
A new window appears and lets you choose the type of Azure Function you would like to create. Let’s keep it simple for now and choose the HttpTrigger function type, which will allow us to use our function as a REST API we’ll be able to call from cURL, Postman, or any custom application.
Select Anonymous in AccessRights (you will be able to change this later) and name the function CreateRestaurant.
Press the Create button. A CreateRestaurant.cs file gets created with boilerplate code in the public static async Task
Let’s take a closer look at that Run(...) method:
- First, note the FunctionName attribute that determines your function url (so use caution if you want to update it).
- Second, the AuthorizationLevel is set to Anonymous as previously configured when creating the function. There are ways you can enforce authentication and authorization using OpenID Connect with Windows Azure Active Directory, Facebook, Google or Twitter (as acknowledged by Microsoft), but we’ll leave it to identity experts to fill in the gaps.
- Third, the get and post parameters indicate that the function can be called with the GET or a POST Http methods. Typically, the GET method is used to retrieve data, the POST method to create data, the PUT method to update data, and the DELETE method to, well, delete data, as you guessed.
Since we only want to use this function to create a document in MongoDB, let’s remove the get parameter and let’s keep the post parameter.
We’ll create another function that we’ll use to retrieve, update and delete. However, we’ll use the HttpTriggerWithParameters function type as it will allow us to provide parameters (such as the restaurant id to retrieve, update or delete) as part of the API endpoint url. Following the same process as above, create another RestaurantFunction.cs Azure function file and name that function Restaurant.
Write CRUD queries to MongoDB Atlas
Now that our 2 functions are set up, let’s move to the meat of this blog post: interact with MongoDB Atlas by writing CRUD queries. In order to write any C# application connected to a MongoDB database, you need the MongoDB .NET driver. An Azure function is no exception to the rule so let’s go ahead and install it with NuGet. Right-click on your Visual Studio project and select Manage NuGet Packages. In the NuGet Package Manager, select the Browse tab and search for MongoDB. In the search results, select MongoDB.Driver, make sure you choose the latest version of the driver and press Install (v2.4.4 at the time of writing).
The MongoDB .NET driver requires dependent assemblies (MongoDB.Bson and MongoDB.Driver.Core) so accept the Apache 2.0 license for these 3 libraries:
The MongoDB driver also depends on the System.Runtime.InteropServices.RuntimeInformation assembly (v4.0.0), which the current version of the Azure Function Tools don’t automatically import with the MongoDB.Driver package (as other Visual Studio project types do). We therefore need to explicitly import it with NuGet as well:
Once that’s done, edit the CreateRestaurantFunction.cs file, and add the following using statements:
Next, delete the content of the Run(...) method in the CreateRestaurantFunction.cs file and replace it with the following:
Replace the entire content of the RestaurantFunction.cs file with the following code:
Note that I made several changes to that function. Namely, I changed the signature of the Run() method to make it asynchronous and I enabled it to handle GET, PATCH and DELETE http requests (as mentioned above).
Note also the RunPatch() of the code where I make use of the BsonDocument and UpdateDefinition objects to update an existing document given an arbitrary (but valid) JSON string:
This would allow me to update the cuisine and borough properties of an existing document by sending the following JSON to the /api/Restaurant/[restaurantId] endpoint of the function:
{
"cuisine": "Italian",
"borough": "Manhattan"
}
The same piece of code would also be able to update the zipcode and building property of the address sub-document by setting JSON attributes with dot notation:
{
"address.zipcode": "99999",
"address.building": "999"
}
Note that if you prefer to use sub-document notation, such as
{
"address":
{
"zipcode": "99999",
"building": "999"
}
}
then you should use a simpler form (in order to preserve the sub-document attributes you don’t update):
update = new BsonDocument("$set", changesDocument);
At this point, our function doesn’t compile because it misses an additional, singleton RestaurantsCollection class, responsible for instantiating a MongoDB database connection and returning a reference to the restaurants collection. The purpose of this class is two-fold:
- Encapsulate similar code we’d otherwise have to write for each function
- Only instantiate a new database connection if none already exists.
Indeed, an Azure function has the ability to reuse the same underlying operating system it uses as its core runtime across close enough calls, thereby allowing us to reuse any database connection we’ve already established in a previous call.
Add a RestaurantsCollection.cs class file add paste the following content into it:
Connect the Azure function to MongoDB Atlas
The last step is to configure our function so it can connect to MongoDB. To do so, edit the local.settings.json file and add a MongoDBAtlasURI attribute inside the Values nested document:
While you test your Azure function locally, you can use your local MongoDB instance and specify http://localhost:27017. However, since you will publish your Azure function to Microsoft Azure, I recommend that you use MongoDB Atlas to host your MongoDB database cluster since MongoDB Atlas is by default secure, yet publicly available (to configurable IP addresses and specific database users). If you don’t have a MongoDB Atlas cluster yet, sign up now and set up a MongoDB Atlas database on Microsoft Azure.
You can retrieve your cluster’s connection string from the MongoDB Atlas portal by pressing the Connect button on your cluster page:
Next, you should press the Copy button to copy your MongoDB Atlas URI to your clipboard:
Then paste it to the local.settings.json file and modify it to match your needs. If you chose Microsoft Azure to host your 3-node MongoDB Atlas replica set, the format of your connection string is the following:
mongodb://<USERNAME>:<PASSWORD>@<CLUSTERNAME_LOWERCASE>-shard-00-00-<SUFFIX>.azure.mongodb.net:27017,<CLUSTERNAME_LOWERCASE>-shard-00-01-<SUFFIX>.azure.mongodb.net:27017,<CLUSTERNAME_LOWERCASE>-shard-00-02-<SUFFIX>.azure.mongodb.net:27017/<DATABASE>?ssl=true&replicaSet=<CLUSTERNAME>-shard-0&authSource=admin
While you’re at it, press the Add current IP address button to allow your current machine (or virtual machine) to access your MongoDB Atlas database:
Test the Azure function locally
It’s now time to run and test our Azure function. Launch the Azure Functions debugger in Visual Studio; the following command line prompt should appear:
Now run the following cURL commands (cURL is available with Cygwin, for instance) or use Postman to craft the equivalent commands.
To create a restaurant document, run:
If you used Postman, you should get a 200 OK result:
Now, try to retrieve the restaurant by running the following curl command:
Next, you can try to update the restaurant by issuing a PATCH request:
Last, delete the restaurant with a DELETE Http request:
Deploy the Azure function to Microsoft Azure
Now that we’ve verified that all the tests above are successful, let’s move forward and deploy our function to Azure. You can deploy your Azure function using Continuous Integration (CI) tools such as Visual Studio Team Services (VSTS) or the Azure CLI, but we’ll take a simpler approach in this post by using the Graphical User Interface available in Visual Studio 2017.
Right-click on the MongoDB.Tutorials.AzureFunctions project, select Azure Function App and press Publish.
The Create App Service wizard appears and lets you configure your Azure App Service name, as well as the subscription, resource group, app service plan and storage account you want to use for that function:
When you’re done configuring all these parameters, press Create.
Configure and test the Azure function running on Microsoft Azure
The Visual Studio deployment process publishes pretty much all of your Azure Function artifacts, except the local.settings.json file where we configured the MongoDB connection string.
In order to create it on Azure, head over to your Azure function in your Azure portal and select the Application Settings link:
In the App Settings section, add the MongoDBAtlasURI key and set the value to a valid MongoDB Atlas connection string.
We’re not done yet though. Unless you have allowed any IP address to have access to your database cluster, we must configure the IP Whitelist of your Atlas cluster to let Microsoft Azure connect to it. To do so, head over the Platform features tab and select Properties.
In the properties tab, copy the comma-delimited list of IP addresses and enter each one of them in your Atlas cluster’s IP whitelist.
Once you’re done, your cluster’s IP Whitelist should have 5 Azure IP addresses along with your local machine’s IP address:
You can now replace the http://localhost:7071 url you used in your cURL scripts or Postman with the url of your published Azure function (such as https://restaurantappfunction.azurewebsites.net) to test your published Azure function. The screenshot below shows the successful result of an /api/CreateRestaurant call in Postman, which is evidence the published version of Azure Function was able to connect to MongoDB Atlas.
Conclusion
I hope you have found this tutorial helpful to get started with Azure Functions and MongoDB Atlas. Cherry on the cake, you can find the complete source code of this tutorial on GitHub.
As a next step, I suggest that you download MongoDB Compass to visualize the documents you just created in your MongoDB Atlas database cluster with our CreateRestaurant Azure Function. Here’s a small tip: if you just copy an Atlas connection string to your clipboard and start MongoDB Compass, it will automatically detect your connection string and offer you to pre-populate the login screen. Pretty neat, no?
If you’re planning to use Azure Functions for a production deployment, you might also be interested in the available continuous integration deployment options offered by Microsoft. And if you don’t already have your MongoDB Atlas cluster, sign up now and create a MongoDB cluster on Microsoft Azure in minutes!