Tweet Posting: Using Azure
Updated: Jul 12, 2021
If you have any questions feel free to comment on this post about it.
In this post we explore some of the capabilities of Azure. More specifically, KeyVault and storage accounts and publishing some code to our shiny new function :).
If you haven't already I wrote a post all about Azure Function Apps. It goes into more depth that I'll be going through here:
Step 1 - Planning our Resources
Ok, so first of what do we actually need to create? Well we need:
. Someplace to store our sensitive info (KeyVault)
. Someplace to store .txt files (container)
. Code (we can do this in the portal)
Step 2 - Setting up KeyVault
First up on the list is to create a KeyVault account. Now what is so special about KeyVault? I hear you ask. Well astute reader, KeyVault enables us to store super secret information and only allow certain users to preform CRUD commands on it. This is done through the concept of "Access Policies" but, more on that later. Right now all we should be doing is setting up a KeyVault resource.
Same as last time search for KeyVault in the "Add resources" tab and give it a name and click "Review + create". When it passes the validation click create.
Cool, now onto access policies. An access policy is basically a contract. Who has permission to access what. Simple as. Now, we have to define the what. In this instance that refers to secrets that we will be storing in KeyVault and, what we want is to allow the Function App to be able to retrieve and list them. So... how do we do it? Simple. First go to your Function App, into "Platform Features" select the "identity" option under "Networking" and turn the status to on. Save and confirm.
Cool, you'll see that that gives us an "Object ID". This what we are going to be referring to when we create our access policy for KeyVault.
So... over to KeyVault. You'll want to select "Access policies" under the "Settings" header. Click add access policy. Now, in the field "principal" click on it an a drop down should be on your right. Select your function app. The click select.
Finally to finish setting up the access policy you'll want to select some permissions so. Under "secret permissions" you'll want to select "get" and "list".
Then click "add" and finally "Save". Good, we have our access policy set up. Neat!
Step 3 - Setting up a Container
This one is fairly straight forward. In your resource group, select your storage account. It would have been setup when you created the Function App.
In here click on "Blobs" either in the main panel or under the "Blob service" heading. Now i here you'll see two folders, both of them are related to the Function App that we had created. They are used to store information about the Function App.
You should see a "+ Container" click it. Enter a name and set the "Public Access Level" to private. When done click ok, to start creating the container.
Well that wasn't so bad at all.
Step 4 - Code!?
Ok, so we could go to our Function App and we could create a new Function in there and edit it and... no. We are doing this properly, first off set up your environment to be able to create Function Apps. If you haven't done so already. Of course you'll need the Azure Function extension for Visual Studios as well as the Azure Cli tools.
Assuming that you have everything set up, we are going to be creating a new Function App... in Visual Studios.
Simply put (see what I did there), select the Azure Function project template in Visual Studios and create it. When prompted you should select the Http trigger function type.
Now this is what your typical Http trigger will look like.
As you can see... it doesn't do much. What it does is, if you set the query parameter "name" in the request to it. It will return a 200 status code with a bit of text and the name sent to it. We don't need to do any of that. In fact you should delete the Azure Function and create a new one. I've called mine "SharePost" (again it's another Http trigger).
Don't worry about the other files in the project we'll get around to them later.
Step 5 - The Actual Code...
Great, now on to the code. What this function is going to do is, it is going to be taking in a request body in the form of a Json object and then manipulate it and send it to both of the integrations. Furthermore, the request should have a property in it to say which integrations are to be used. So our first step is then to model the data as such:
Now, seeing as how this object is going to be serialized as a Json, we can/ are going to be using an attribute in the Newtonsoft library to mark properties such that if the data coming in has a name change it's not going to break...
The final thing about this class is the use of an enum, this is going to be used to say which integration we are going to be sharing our shiny new post to.
Step 6 - Testing Introduction
Now before we go any further... one of the things I really, really like doing is called TDD. Basically what it means is that we will be writing tests whenever we can find a use case for it. The reason for this is to make our code more robust, and less prone to bugs.
To do this we have to add a new project to our current solution. This new project is going to be an Nunit Test Project (.Net Core). This project will need a reference to our Azure Functions Project as well.
The core concept of TDD is to test first and fail often. The reason for this is so that we only write enough code to make our tests pass. It's a great way of adding confidence to what you write as the tests act as proof of what you have been doing. I find that it's something that is better off being added at the start rather then at the end of a project.
Viewing and running Nunit tests in VS is very easy. Click on the test tab at the top for the screen, and the open the test window. From here you can pretty much do anything that you want to (test related, anyways).
Step 7 - Real Tests
Cool, on to testing out the Function :) The test that we want to write is that if no request body is found then throw 400 status code. Our test should look some thing like this.
Notice the attributes. We are defining a test, and it will pass if a 400 is thrown, when we don't send in a request body. I'm not going to go through all of the code but, a brief explainer on each class. The HttpRequestCreator class does as it says, it's used to create HttpRequests.
This is the updated code for our function app. It checks for an empty string then it throws a BadRequestObjectResult.
Cool, but... what if pass in a proper request body but... it's missing info. Oh well seems like we need even more tests. The scenarios are as follows:
. Request body is not null but everything else is
. Request body is not null but PostUrl is
. Request body is not null but PostContent is
. Request body is not null and has data in each property
Instead of writing a new method for each case we can do this really cool thing called a TestCase. Essentially it's a way to test out different values with our tests and see what happens. Here are some I prepared earlier:
See... much better! We are failing successfully :)
Step 8 - Publishing
Great! We managed to code a function that when run throws the correct errors. Cool. However... it only works locally for now. We don't want that. So, our next step is to publish our code to our function app, and then hit the function app to see what happens. First off... the publishing.
To publish, make sure that you are publishing the function app and not the test project. You can find the publishing option under the "Build" tab in vs. Select use existing, then click publish. Fill out the details and find your function app in the drop-down menu. Click "ok" and away you go.
If that doesn't work, stop the function app in the portal then try to publish again. Then start it again. And with that you should be able to see your new function in the portal.
Step 9 - Finial, Final Testing
Ok, so we have tested it locally and it's pretty good. However, there is no guarantee that the live version is going to work. The only way to test that is if we test it in Postman. Now, Postman is a tool used for sending Http request. Because our function requires a request body we have set it up to take post requests. So here is the sample request that I have made to test it in Postman:
And as you can see it works perfectly fine :)
Right well, I'm not so sure about you but my fingers are exhausted from all of this typing. So, this seems like a good place to drop it for now.