Serverless in Context
Getting the Most From Azure Functions
*** A newer, updated version of this course is available here. ***
An Introduction to Azure Functions
Serverless Computing has emerged as a capable and low-friction means to execute custom logic in the public cloud. Whether you're using Amazon Lambda, Google Cloud Functions, or Azure Functions, you have a wide variety of target languages, ecosystem integrations, and deployment mechanisms to choose from. All this while leaving the heavy lifting of server provisioning and maintenance to the experts, which gives you plenty of time to focus on your differentiated application functionality.
In this "Introduction to Azure Functions" course, you’ll learn how to build Azure Function applications in the cloud. You'll discover the core feature set of Functions and see how to integrate with a variety of sibling Azure services. You'll explore Function topics like security, monitoring, deployment, and testing best practices. You'll also learn about ideal Functions use cases and the pricing model. Finally, you'll learn about how we've arrived at the serverless computing model, and where serverless is likely to go in the future. By the end of this course, you’ll have a solid foundation to continue exploring Functions on your own, and incorporating Azure Functions capability into your work.
An Introduction to Azure Functions: What You'll Learn
|Lecture||What you'll learn|
|Intro||What to expect from this course|
|Serverless Computing In Context||Understanding what serverless computing is, and how we got here|
|Core Features||A high-level overview of what Azure Functions is, and its basic capabilities|
|Creating Your First Function||A demo of creating your first function in the Azure portal|
|Security||A review of security features in Azure Functions|
|Using API Key Management||A demo of configuring an Azure Function to require API key use|
|HTTP Proxies||A discussion of lightweight HTTP Proxy support|
|Proxying Azure Blob Storage||A demo of using Functions' HTTP Proxy support to front Azure blob storage|
|Triggers and Bindings||Event-based triggering of functions and declarative binding of inputs and outputs|
|Triggering on Queues and Binding to DocumentDB||A demo of Triggering with Azure Queues and Binding Function Output to DocumentDB|
|Testing and Debugging||Tools and techniques for working with Functions during the development cycle|
|Deployment||Options for deploying Azure Function apps into production|
|Deploying From a Local Git Repo||A demo of deploying a complete Azure Function app to the cloud, from a local Git repository|
|Monitoring||Tools for monitoring Azure Functions during dev, test, and release|
|Use Cases||A discussion of ideal use cases for serverless compute and Azure Functions|
|Pricing||A review of how Functions are priced, and a demo of determining price using the Azure Pricing Calculator|
|Serverless in the Future||A short discussion on the future of serverless in the cloud|
|Summary||Course wrap up|
If you have thoughts or suggestions for this course, please contact Cloud Academy at firstname.lastname@example.org.
Okay so now let’s take a look at creating an Azure function, which is triggered via an HTTP call, and we'll also configure the API key access mechanism for it, so that we can get a little bit of extra security.
So recall that our previous function we created was just a manually triggered function, so let's create a new one that's going to use the HTTP trigger. And to change it up a little bit, our last one was a, the last one we created was a Node.js based function, so this time we'll use C#, and we'll use the HTTP trigger.
So we'll keep kind of the default name, just so we know what it is, and this time we wanna use different authorization level, we wanna use the the API key that we define at the function level. So I will create that here. Okay. So when we create the function, you can see that we have, we get this .Net C# boilerplate code. We're bringing in System.Net namespace, and then we just have a single function, statically, a static function, which returns, or it accepts an HTTP request message, and optionally a TraceWriter that we can use to write to, we can actually omit that if we don't intend to use it. And then it returns a task, since this is an asynchronous function, returns a task of HTTP response message.
So the function gives you some boilerplate code for accessing either the query string parameters as named value pairs, or optionally the body, the data that comes in the HTTP request message body itself. It gives you some code for accessing both sets of data. And you can use this of course to, you know, as the basis for your own custom logic which will interrogate incoming data, process it in some way, and then generate a response. So you can see basically this code looks either for the presence of a query string parameter called name, or it looks for some data in the body which would correspond to the name. And whichever one, whichever one comes back, it uses that as the name and it returns a HTTP response saying hello name, or if one isn't passed in, then it returns an error to the calling code. So again, its just a really simple boilerplate example, nothing too interesting in and of itself but, but again easy enough to build upon to create your own custom logic.
So we'll test this real quick in the browser. We've already opened, see we've already got the test window opened up here on the right hand side. So we want to use the Post HTTP method since we will potentially be passing data in, to the, in the request body, we'll need to use a post. We can use a query, again, we can use a query string parameter if we want to, in fact I can show you that in just a second, but we'll start with the HTTP request body and we'll say Josh instead of Azure.
So if I save this and run it, then we should see, down at the bottom, yeah, we can see some output here, “hello, Josh”, this is our response, you can see we've got an HTTP 200 which indicates success or okay, and our response was “hello, Josh”, and you can see the log output down below, that the function started, the trigger, the HTTP trigger processed the request, and then the function completed. So, and again, this log information here corresponds to this line of code up above, saying hey we've initiated execution or invocation of this function.
So if we wanna switch this up a little bit we can add a query string parameter, and we'll call it name, and we'll call, we'll pass in a different name, Fred, and I will actually remove the body in this case, and we'll run again. You can see, again, we get success, the, oops, the function invocation was much faster this time because we're now already compiled and running in memory so invocation was much quicker this time, and again, we get function started, we get our log message, and function succeeded. So that's exactly what we expect.
Alright, so now let's make this a bit more interesting, and instead of calling this from in the browser, which is only modestly interesting, let's call this from some external, from some external tool. So the tool we're going to use is something called Postman. And Postman is a really nice, there are actually a number of these kinds of tools freely available, this is a really nice one that you can download and use for free, that allow you to invoke a HTTP API's, publicly accessible API's, and you know, you can specify custom query string arguments, and custom header values, and then, and sort of interrogate the responses that you get back and kind of see what they look like, and then just a nice way of doing some level of ad-hic testing of HTTP API's.
So in order to use this, the the first thing I need to do is I need to get the URL that I'm gonna call from my function. So if I click on this button on, this link right up here, the upper right side of the editor window, then, and I'll put it into Postman, here we go. The first part I get is just this URL prefix for my application and then it's configured to use “/api/function-name”. So you can see that here. And then this last bit is this, this kind of ugly looking code. This code corresponds to one of the function keys that is created for me automatically when I, when I created the function. And this is what allows me to call into the function app itself. If I omit this code then I won't be allowed to, my request won't be allowed to succeed, it will automatically be rejected by the Azure function app infrastructure.
So if I look at this, just to show you kind of what's going on here, if I look at, oh let's see this should be on the, ah we have the keys over here, here we go, so if I look at this function key, if I switch back to my app, yeah you can see that it's, it's the same one. FiR blah blah blah blah blah, and then ends with Euw==. So it's just a big long ugly string which again is, just serves as a key to hand out to clients and only clients which pass in a valid key are then allowed to call your function. So of course you can change the key as you need to, kind of recycle it, you can, you can revoke a given key, and say this key is no longer valid. You can specify multiple keys if you want to, I only have one here but, but you can sort of, you know if you want to say have multiple keys, to have multiple, to sort of handle multiple types of client, client access, then you can reject them or recycle them as needed, to ensure that only authenticated, or valid clients are allowed to, allowed to call into your function.
If we go back to Postman, then we can specify a couple of things, and call into, call into our function. So the first thing I'm gonna need, we'll, we will specify, we're gonna do a post here of course, so the first thing we're gonna need is to specify a content type. Because this will tell, this will tell our Azure function infrastructure that we're passing in some JSON data in our request. So if I specify the body of the request, we'll use raw here, now I'm just gonna specify some JSON. We'll say name, and we'll use “Sally” as our name. And again, we're telling the Azure infrastructure, the web server essentially, that this data that we're passing in our body is JSON data.
So if I click send here, then you can see down below, I get hello Sally in my response. I get an HTTP 200, meaning that it was successful. And it took 192 ms, Postman just kind of tells me the roundtrip time from, from client request initiation to receiving the response from the server.
If I flip back to the portal, you can see, for that given invocation, you can see that again I have these kind of these book end events that are logged for me. The function started, then we write to our log, from our method itself, and then, we, the function completes successfully. So if we, just to kind of close the loop here, and demonstrate what can happen if we omit this code, if I just leave this off then and if I click send, then you can see I get 401 unauthorized, meaning that I'm not a, Azure functions is rejecting my request, and I'm not allowed to invoke it because, precisely because I haven't specified the key.
About the Author
Josh Lane is a Microsoft Azure MVP and Azure Trainer and Researcher at Cloud Academy. He’s spent almost twenty years architecting and building enterprise software for companies around the world, in industries as diverse as financial services, insurance, energy, education, and telecom. He loves the challenges that come with designing, building, and running software at scale. Away from the keyboard you'll find him crashing his mountain bike, drumming quasi-rythmically, spending time outdoors with his wife and daughters, or drinking good beer with good friends.