Azure Functions vs Web APIs: Which is the Right Tool for Your App?
Disclaimer: The focus will be on Azure and Microsoft products!
Serverless architecture has changed the way how developers build and deploy applications, offering scalability, flexibility, and cost-efficiency. In this article, we’ll explore the differences between these approaches, when to use each, and how to build robust serverless applications using .NET and Azure Functions. We’ll also dive into event-driven architecture, discuss patterns, limitations, and real-world use cases, and provide guidance on creating scalable systems with these tools.
Short Intro to Serverless Architecture
Serverless architecture allows developers to focus on writing code without managing infrastructure. With .NET, you can do it in AWS using Lambda and Step Functions and on Azure by using Azure Functions and Durable functions. Simple things can be done by using Lambda or Azure Functions and for workflows, you’ll need Step Functions or Durable Framework (Durable functions).
As earlier said, we will focus on Microsoft products, so, in Azure at least, the most used triggers for the functions can be HTTP requests, timers, and different events (all triggers and bindings can be found here).
The biggest benefits of this architecture are:
Benefits of serverless architecture:
- Auto-scaling: Resources scale dynamically based on demand.
- Cost-efficiency: Pay only for the resources consumed (and the free plan is pretty ok for most apps).
- Quick deployment and no OPS: Focus on business logic without worrying about infrastructure. You don’t need to manage or maintain servers or OS.
- Availability: Azure Functions automatically distribute workloads across multiple regions, ensuring high availability without additional configuration. Actually, I find it harder to configure not to do this and keep everything in one region (you need to create your own policies and so on).
- Integration with Event Sources: You get out-of-the-box connectors to services like databases, message queues, and storage systems, simplifying integration and you get reduced boilerplate code.
- Environment Isolation: Each function runs in a separate environment, reducing the risk of one process affecting another one so it’s increasing overall application resilience.
All in all, what you need to remember from here is that Azure Function is a Function-as-a-Service (FaaS) which should be used to do a single-purpose thing.
The Traditional Approach — Web APIs
Web APIs are the cornerstone of building (RESTful) services. With .NET, developers can create robust APIs that expose endpoints that can do anything.
The main advantages that I can think of are:
- Easy to configure routing and middlewares: Support for fine-grained control over request processing.
- Flexibility: You can build any kind of business logic, architecture and project design. You can also host it anywhere you want (cloud, on-prem, containers), so you’ve got a “vendor independence”.
- Easy to understand: Every junior knows about it, and you can build from monoliths to microservices using it.
- Long-Running Operations: You don’t have a time limit for running it (execution time) like you have on Azure functions.
Key differences
There are other differences of course, like the granularity that we already scratched the surface of, the routing, the response formats, the way how monitoring is done and so on, but for me, those 5 things are the most important ones that I used in practice (so far).
When to Use Azure Functions
Azure Functions shine in scenarios requiring scalability and event-driven processing.
- Event-Driven Applications: React to events in real-time, such as message queues.
- Batch Jobs: Schedule tasks with time triggers (for example delete users after a period of inactivity).
- Microservices: Split monolithic applications into independently deployable, single-purpose functions.
- Workflows with Durable Functions: Orchestrate complex workflows that require retries, parallel tasks, or chaining. (Orchestration vs Choreography)
Example Use Case: Serverless File Processing
- A system that processes uploaded files in Azure Blob Storage could use an Azure Function triggered by the BlobTrigger. The function could process the file, save results in a database, and send notifications.
- As already mentioned the deletion of users after a period of inactivity. A timer-triggered function selects the users to start the deletion from a database and throws events or makes HTTP calls to other functions to clean up also their data.
When to Use Web APIs
Web APIs are ideal for creating stateful services with multiple endpoints and “hard-core” business logic. As a simple example, I always go towards this when I have session management (use cookies, tokens or other things like this to maintain a state)
Combining Azure Functions with Web APIs
In many scenarios, Azure Functions and Web APIs work better together. Azure Functions can handle background tasks or event-driven processes, while the Web API may serve the front-end interface and long-running processes.
The UI part can also be served by HTTP endpoints of Azure functions, but it’s all about what you want and have over there.
Real-World Cases with Azure Functions
- IoT Data Processing: Process data from different IoT devices it’s a perfect use case for functions.
- Serverless APIs: Have an API to quickly retrieve or save some data and stop.
- Workflows: This can be done easily with Durable Functions, but if you have A LOT of functions running and A LOT of instances if your storage gets to more than 300–400GB without you cleaning it, you might get into random issues (like activities scheduled and running more then once). Keep your “table” clean and split your functions as much as you can. It’s not a WebAPI!
- Stateless Nature: If you want to manage your state manually across your function execution you might go mad before you manage to get it done.
Design Patterns and Other Big Words Used in the Serverless World
- Fan-Out, Fan-In: Start multiple Azure Functions to process multiple tasks in parallel and aggregate results. You can think of running multiple Activities that do calls to other services or save something in a CosmosDB.
- Chaining: “Link” multiple functions in a sequence using Durable Functions (Durable Framework).
- Retry Logic: Implement fault-tolerant systems with retries for transient errors.
- Pub/Sub: Use Azure Event Grid or Service Bus (or anything else that you want or have) for publish-subscribe messaging patterns.
Key Considerations
In Azure Functions “world” you’ll get a cold start on the free plan. The latency is not that bit, but it is, so if you want an always-on and available endpoint, upgrade to the premium plan. You can also ping it and keep it alive, but most likely you might get into trouble and pay more than you should.
Another thing to consider is that you’ll get a Vendor lock-in. To move a function to AWS for example, it’s not just a copy-paste.
Debugging is more complex in the serverless world and without open telemetry and a good plan on how when and what to log, you might find yourself in problems without a solution. With a WebAPI you almost have no complexity at all when you are debugging.
Conclusion
To do one or the other actually, it’s a pretty simple decision. It all ends up with how complex is the system you need to build and how large is it. What are your limitations? Probably the best way is to have both of them, but are you able to do it (actually is your organization allowing you to have functions)? If you are allowed to use a serverless approach, probably you’ll end up with a hybrid approach and have both of them, which as you already saw, it’s not a bad thing!