How to Create a REST API with Azure Functions and the Serverless Framework — Part 1
Originally posted at Serverless on Sep 17, 2019
Overview
With the recent updates to the serverless-azure-functions plugin, it is now easier than ever to create, deploy and maintain a real-world REST API running on Azure Functions. This post will walk you through the first few steps of doing that.
To see the full end-to-end example used to create this demo, check out my GitHub repo. I structured each commit to follow the steps described in this post. Any steps named Step X.X are steps that involve no code or configuration changes (and thus not tracked by source control), but actions that could/should be taken at that point in the process. This is done to preserve the "commit-per-step" structure of the example repo.
This post will only cover the basics of creating and deploying a REST API with Azure Functions, which includes step 1 and step 2 from the example repo. Stay tuned for posts on the additional steps in the future.
I will make the assumption that you have the Serverless Framework installed globally. If you do not (or have not updated in a while), run:
Also, the serverless CLI can be referenced by either serverless or sls. I will use sls in this post just because it's shorter, but serverless would work just the same.
Step 1: Create your local Azure Function project
Let’s begin by creating our Azure Function project with a template from serverless.
The resulting project will be in the directory sls-az-func-rest-api. cd into that directory and run npm install. To make sure you have the latest version of the Azure Functions plugin, run:
It’s important to note that the generated serverless.yml file will contain a lot of commented lines, which start with #. Those are purely for your benefit in exploring features of the Azure Functions plugin, and can be safely removed.
Step 2: Add your own handlers
For the sake of this demo, we’re going to create a basic wrapper of the GitHub API for issues and pull requests.
As you’ve probably already noticed, the azure-nodejs template comes preloaded with two functions: hello and goodbye. Let's remove those before we start adding our own code. To do this, remove both the hello.js and goodbye.js files. Also, remove their configuration definitions from serverless.yml.
Right now your file structure should look something like:
and your serverless.yml should look like (not including any comments):
Add Code
Let’s add in our own code. We’ll start by creating the directory src/handlers. This, perhaps to your great surprise, will be where our handlers will live. Inside that directory, we will put our two handlers: issues.js and pulls.js.
Just for fun, we’ll also add a utils.js file for shared utility functions across handlers, and we’ll put that just inside the src directory.
You’ll also note that the handlers are using a popular NPM package for HTTP requests, axios. Run npm install axios --save in your service root directory.
Current Folder structure
Now we need to add our new handlers to the serverless configuration, which will now look like:
Step 2.1: Test your API Locally
Run the following command in your project directory to test your local service.
This will generate a directory for each of your functions with the file function.json in each of those directories. This file contains metadata for the "bindings" of the Azure function, and will be cleaned up when you stop the process. You shouldn't try to change the bindings files yourself, as they will be cleaned up and regenerated from serverless.yml. If you make changes to your serverless.yml file, you'll need to exit the process and restart. Changes to code, however, will trigger a hot reload and won't require a restart.
Here is what you can expect as output when you run sls offline:
When you see the “Http Functions” in the log, you are good to invoke your local service.
One easy way to test your functions is to start up the offline process in one terminal, and then in another terminal, run:
Let’s create a file with some sample data at the root of our project, and we’ll just call it data.json:
Luckily, owner and repo are the same parameters expected by both the issues and pulls handlers, so we can use this file to test both.
We’ll keep our offline process running in one terminal. I'll open up another (pro tip: use the "Split Terminal" in the VS Code integrated terminal), and run:
Here’s my output:
You can see that it made a GET request to the locally hosted API and added the info from data.json as query parameters. There are no restrictions on HTTP methods, you would just need to specify in the CLI if it's not a GET. (Example: sls invoke local -f pulls -p data.json -m POST)
You could also run a simple curl command that would accomplish the same thing:
And here is the output in the terminal running the API. You can see our console.log statement from the handler output here:
When I’m done running the service locally, I’ll hit Ctrl/Cmd + C in the API terminal to stop the process. You can see that it cleans up those metadata files we discussed earlier:
Step 2.2: Deploy
Authentication
That’s all the configuration we need, so we’re ready to deploy this Function App. In order to deploy, we’ll need to authenticate with Azure. There are two options for authentication: interactive login and a service principal (which, if you are unfamiliar, is essentially a service account).
At first, when you run a command that requires authentication, the Interactive Login will open up a webpage for you to enter a code. You’ll only need to do this once. The authentication results are cached to your local machine.
If you have a service principal, you’ll set the appropriate environment variables on your machine, and the plugin will skip the interactive login process. Unfortunately, if you’re using a free trial account, your only option is a service principal. The process for creating one and setting up your environment variables is detailed in the Azure plugin README.
Deploy Command
With configuration and authentication in place, let’s ship this thing. From the root of your project directory, run:
sls deploy
and watch the magic happen. Your app will be packaged up into a .zip file, which will be located in the .serverless directory at the root of your project. From there, an Azure resource group will be created for your application, containing things like your storage account, Function App, and more. After the resource group is created, the zipped code will be deployed to your newly created function app and the URLs for your functions will be logged to the console.
Step 2.3 Invoke Deployed Function
We can invoke a deployed function in the same way we invoked our local function, just without the local command:
(Optional) Step 2.4: Cleanup
If you have been following this tutorial and would like to clean up the resources you deployed, you can simply run:
BE CAREFUL when running this command. This will delete your entire resource group.
Additional Steps
Stay tuned for future posts walking you through other steps of setting up your service, including adding API Management configuration, quality gates like linting and unit tests, adding Webpack support, CI/CD and more.
Also, if you’re going to be at ServerlessConf 2019 in NYC, the Microsoft team is putting on a Azure Serverless Hands-on Workshop on October 7th from 8:30 am to 5:00 pm.
Contributing
We’re eager to get your feedback on the serverless-azure-functions plugin. Please log issues on the GitHub repo with any bug reports or feature requests. Or better yet, fork the repo and open up a pull request!
Part Two of this tutorial can now be found here.
Originally published at https://www.serverless.com.