Serverless Cloud Native REST APIs with Azure Functions
Most modern web applications are built by separating so-called backend and frontend implementations. The backend runs on a server and the frontend is executed in a web browser. These two communicate with each other via an application programming interface (API). In many cases, this API is an HTTP-based representational state transfer (REST) API. There exists other kinds of APIs and means to exchange data between the backend and the frontend, but I’ll focus on REST APIs in this blog post.
Deploying, running and scaling the backend requires quite a bit of configuration on the infrastructure side. Managing all this by yourself is a complex and time-consuming approach to backend API development. Luckily, cloud providers have services that remove this burden and allow you to focus purely on the business logic of the application. In Azure, this serverless service is called Azure Functions. Functions are pieces of code that are executed by the cloud platform when some event or request triggers them.
Serverless is a bit misleading term. There are always data centers, servers and other infrastructure under the hood. In the context of the Azure Functions, serverless means that you only need to write the code and the cloud platform takes care of almost everything else. Functions are also very affordable since in the default consumption plan you pay only for the execution of the functions. There’s a generous free quota, and small projects rarely exceed it. In the consumption plan, the functions run only on upon request, and during idle periods they are dormant.
Azure Functions are often used in messaging- and event-based systems for data processing, but I find them equally good for API development in small to medium-sized projects. In addition to the fast development cycle, the Azure Functions tooling provides excellent developer experience with Visual Studio Code and Visual Studio. I prefer personally Visual Studio over VS Code. The function app can be run and debugged with both of these in the local development environment.
The other benefits of Azure Functions are faster time to market, automatic horizontal scaling and very good integration with other Azure services. Authentication is ridiculously easy with Azure AD and managed identity makes it easy to access other Azure services.
The downsides are cold starts in the consumption plan (it takes a few seconds to spin up the function app if it’s not already running) and limited computing power as well as memory. For most basic API-related use cases, these are not an issue.
Architecting Azure Functions API Apps
Azure Functions application consists of multiple functions. In an API app, these functions are called HTTP triggers. Each HTTP trigger function exposes a single API endpoint to the user. For example, if we have an API to fetch and create books, then there’s a function for fetching a list of the books and a function to create a book. For C#, there is an extension that will use the function attributes from the code to create an OpenAPI definition and serve it with Swagger UI for other developers. This will further speed up the development and make everyone’s work easier.
Unfortunately, most Azure Functions tutorials out there do not focus on software architecture. For example, just throwing a bunch of code in the body of each HTTP function trigger is not a very smart move when developing an API with multiple endpoints. It makes it very hard to extend or maintain the application in the future.
I’ll introduce here one approach for architecting an Azure Functions application with C# that will make it easier to develop REST APIs. If you’re familiar with ASP.NET Core apps, this architecture is probably already familiar to you.
In practice, you’ll want to keep the code in the HTTP trigger functions as minimal as possible. Construct the rest of the application by following the Clean Architecture approach and utilizing Azure Functions support for dependency injection. The HTTP triggers will be the presentation layer of the API application you are building. I won’t go into implementation details here, since the architecture is summarized quite well on Microsoft’s documentation page linked above.
In addition to easier development and maintenance, the architecture allows removing the whole Azure Functions runtime dependency simply by modifying the presentation layer’s function triggers (= controllers) to some other framework such as ASP.NET Core. The actual business logic or data access logic is not dependent on the Functions in any way. This means that you can migrate the app easily from Azure Functions to some other place if needed.
Azure Functions is probably the easiest, fastest and most affordable service to create REST APIs in Azure. However, designing and architecting the whole cloud application is another story. It requires an in-depth understanding of the cloud platform since a single cloud service is rarely enough when creating robust cloud architectures. If you are interested in building modern cloud applications, have a look at our cloud-native service offering and contact us.