Moving from HTTP-Triggered Azure Functions to Web API (Update 2019.07.09)

Fireworks over Chicago

This past weekend was a long one due to the Fourth of July, and despite a weekend filled with cookouts, swimming, fireworks, an anniversary date night, and a trip to St. Louis, I was able to knock off an important task on my side project‘s TODO List.

Refactoring HTTP-Triggered Azure Functions into a Web API Service

When I started work on Stock Alerts, I began with the Azure Functions for retrieving quotes and evaluating alert definitions, because they were the most interesting pieces to me.

I then started thinking about the API endpoints that I’d need to support a mobile client. I figured I wouldn’t need too many endpoints to support the very minimal functionality that I was aiming to implement for MVP, and I already had the Azure Functions project, so I figured I’d just stand up a few HTTP-triggered functions for my API. After all, I could always refactor them into their own proper web API project later.

It was midway through implementing authentication that I realized that rather than continuing to try to fit the endpoints that I needed into Azure Functions, it made sense to move the HTTP-triggered functions into their own web API project with a separate app service in Azure sooner rather than later.

So that’s what I did.

I performed the refactor Thursday/Friday, and fiddled with the build and release pipelines in Azure DevOps in my free moments on Friday/Saturday. Monday morning I switched the app to use the new API.

Thankfully the refactoring of the code was fairly simple because my functions, much like good controller methods, were thin – they simply received the HTTP request, deserialized it, performed any necessary request-level validation, and delegated processing to the domain layer which lives in a separate assembly. The controllers in the Web API project that I created ended up being very similar.

I’m now closer to the MVP infrastructure that I mentioned a week ago, depicted below (I’m just missing StockAlerts.WebApp now):

Stock Alerts MVP Infrastructure Resources

I love the feeling of checking items off of my TODO list.

Why I Chose Web API Over HTTP-Triggered Azure Functions

So why did I choose to move my API methods from my Functions project to their own Web API project and service?

A few key reasons: 1. Inability to configure middleware for Azure Functions 2. Prefer controller methods over Azure Functions 3. API usage patterns

Let’s talk about these one-by-one…

ASP.NET Core Middleware

ASP.NET Core gives the developer the ability to plug in logic into the request/response pipeline. This logic is referred to as middleware. Andrew Lock has a great post on what it is and how it works in an ASP.NET Core web app.

ASP.NET Core has default middleware that it executes during the normal course of processing a request and response, but it also allows the developer to configure at startup what additional middleware should execute with each request, including custom middleware. Middleware is generally used for performing cross-cutting tasks – things like logging, handling exceptions, rendering views, and performing authentication, to name a few.

Early in my adventures into Azure Functions I learned that the developer doesn’t have the ability to configure the middleware that executes during an HTTP-triggered function invocation. Sure, some folks have rolled their own middleware pattern in Azure Functions (like here and here), but I didn’t want to invest that much effort into building something that an ASP.NET Core Web API gives me for free.

My custom middleware needs aren’t too many: for a typical web API I add custom error-handling middleware and enable authentication middleware.

Though I was able to implement workarounds to accomplish these tasks to work in my functions, they weren’t nearly as clean as accomplishing the same thing with middleware in an ASP.NET Core Web API.

Error Handling

My preferred approach to handling exceptions on recent Web API projects has been to create an ErrorHandlingMiddleware class that catches any unhandled exception during the processing of the request and turns it into the appropriate HTTP response. The code can be found here. Adding it to the pipeline is as simple as one line in Startup.cs:

app.UseMiddleware(typeof(ErrorHandlingMiddleware));

To accomplish similar functionality in my Azure Functions required an additional Nuget package (PostSharp), a custom attribute, and a [HandleExceptions] on top of all of my functions. Not terrible, but I’d rather not have the extra package and have to remember to manually decorate my functions to get error-handling.

Authentication/Authorization

To turn on token-based authentication/authorization for an ASP.NET Core Web API endpoint, you must configure the authentication, JWT bearer, and authorization options in Startup.cs, add the authentication middleware with app.UseAuthentication();, and decorate your controller methods with the [Authorize] attribute.

To implement token-based authentication/authorization on my Azure Functions, there wasn’t an easy way for me to simply decorate a function with an [Authorize] attribute and let the framework make sure that the user could invoke the function. Instead, for each function I had to use AuthorizationLevel.Anonymous and manually check for a valid ClaimsPrincipal and return new UnauthorizedResult() if there wasn’t one.

It worked, but it wasn’t pretty.

Beyond that, I had trouble getting it to add the Token-Expired header on responses when the auth token has expired. After switching over to Web API, this just works with the configuration I have in place.

Prefer Controllers Over Functions

As I began to add multiple HTTP-triggered functions that manipulated the same server resource, I grouped them into a single file per resource, similar to how controllers are often organized. But even though the methods were grouped like controllers, there were significant differences at the code level that cause me to prefer the controller implementations over the Azure Functions implementations.

Let’s compare the two side-by-side…

Here’s an Azure Function for getting an alert definition by ID:

[FunctionName("GetAlertDefinition")]
[HandleExceptions]
public async Task<IActionResult> GetAlertDefinitionAsync(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "alert-definitions/{alertDefinitionId}")] HttpRequest req,
    string alertDefinitionId)
{
    var claimsPrincipal = _authService.GetAuthenticatedPrincipal(req);
    if (claimsPrincipal == null)
        return new UnauthorizedResult();

    var alertDefinition = await _alertDefinitionsService.GetAlertDefinitionAsync(new Guid(alertDefinitionId));

    claimsPrincipal.GuardIsAuthorizedForAppUserId(alertDefinition.AppUserId);

    var resource = _mapper.Map<Resources.Model.AlertDefinition>(alertDefinition);
    return new OkObjectResult(resource);
}

And here’s the analogous controller method for getting an alert definition by ID:

[HttpGet]
[Route("{alertDefinitionId}")]
public async Task<IActionResult> GetAsync(Guid alertDefinitionId)
{
    var alertDefinition = await _alertDefinitionsService.GetAlertDefinitionAsync(alertDefinitionId);

    HttpContext.User.GuardIsAuthorizedForAppUserId(alertDefinition.AppUserId);

    var resource = _mapper.Map<Resources.Model.AlertDefinition>(alertDefinition);
    return new OkObjectResult(resource);
}

Observations:

  1. The controller method is shorter.
  2. The controller method is able to accept ID parameters as GUIDs, avoiding manual conversion.
  3. The controller method declares the HTTP verb and route more cleanly (in my opinion) as method attributes rather than a parameter attribute.
  4. Because I’ve decorated the controller with [Authorize], the controller method avoids the manual authorization logic.
  5. Because I’m using the ErrorHandlingMiddleware, the controller method avoids the extra [HandleExceptions] attribute.
  6. Not illustrated in this example, but the controller method accepts request bodies as entities, avoiding having to manually deserialize the request body from the HttpRequest.

From a purely code aesthetics perspective, I just prefer controller methods over HTTP-triggered functions.

API Usage Pattern

I expect the usage pattern of my API to be fairly uniform across the available endpoints and the traffic to ebb and flow predictably with the amount of users using the mobile app. I don’t expect large spikes in traffic to specific endpoints where I would need to be able to scale individual endpoints; if there are large spikes due to a sudden increase in the number of users, I’ll want to scale the whole web API service.

While HTTP-triggered Azure Functions may be the right choice for other use cases, the anticipated usage pattern of the Stock Alerts API aligns much more closely with a Web API service.

I’m still using Azure Functions for pulling stock quotes, evaluating alert definitions, and sending out notifications. Azure Functions are well-suited for these use cases, for the reasons I described here.

Wrapping Up

With this change behind me, I’m ready to continue moving forward working on the mobile app. My mornings the rest of this week will be focused on building the Create Alert Definition screen.

Here’s the repository for the project if you’d like to follow along: https://github.com/jonblankenship/stock-alerts.

Thanks for reading!

-Jon


If you’d like to receive new posts via e-mail, consider joining the newsletter.

Working on a New Side Project in Public

For the past month or so I’ve been working on a new side project. It’s a small project that will allow me to exercise existing skills, re-sharpen older skills that I’ve not used in awhile, and learn some new ones.

I’d like to share it with you…

Working in Public

I’ve been working my side project every weekday morning for an hour or two before my workday starts and on the occasional weeknight or weekend. I toil away mostly in solitude, except when I solicit feedback or ask for advice from a colleague and buddy who’s working on his own project.

I’ve recently been inspired by a few folks on various podcasts to start working in public. They speak of the benefits of sharing what you’re learning, developing, building with your audience as you’re working on it, an idea that strikes fear in the hearts of those who, like me, are inclined towards self-conscious perfectionism. It’s difficult to put your in-progress work out there for all to see, warts and all.

There’s been an increasing trend towards working in public, particularly among indie makers and developers. I dipped my toe into those waters with my last project, Open Shippers, earlier this year*, and I plan to get back in the pool with this project.

My plan is to post fairly regular (weekly?) updates about what I’m doing on the project:

  • What did I do the prior week?
  • Is there a particular problem I solved, pattern I used, or trick I learned that is worth sharing?
  • What do I plan to work on in the coming week?
  • Any particular challenges worth mentioning?

Things like that.

These will be pretty rough, unpolished posts. Sometimes a particular topic I encounter will be worthy of becoming a more in-depth, polished post, and put these up from time to time.

Goals

So what are my goals with working on this new project, and doing so in public?

  • Get into the habit of writing regularly.
  • Sharpen old skills and learn new ones.
  • Share what I’m working on and what I’ve learned. Hopefully it is helpful to someone.
  • Demonstrate the process of taking a product from concept to market.
  • Demonstrate well-architected, working product on the Azure / .NET Core stack.
  • Teach.
  • Learn.
  • Have fun.
  • Make some lunch money if anyone subscribes to the service.

What’s the Project?

Concept

The idea is not particularly novel or interesting, but it’s a good candidate for what I’m trying to achieve with this project.

I’m building a stock alerts app (hereafter referred to as Stock Alerts until I think of a good name for it) that will allow the user to create an alert definition for a given stock based on a set of criteria that they define. When the alert is triggered, the user will be notified according to their preferences by push notification, SMS, and/or e-mail.

“Aren’t there a ton of other stock alert apps out there?” Yes, there are. Some just let you set a simple price alert; others offer many more features. I plan to support complex alert criteria that include not only simple price alerts, but eventually also technical and fundamental alerts as well, which will differentiate the app from a portion of the market.

I also want to challenge the idea that you have to have a completely novel idea to succeed in building an app that people will pay for. There’s room for multiple competitors in most markets, and oftentimes your app will be the right choice for a segment of the market that’s not currently being served well.

To be clear, I have no illusions of replacing my income with this app, but it will be great fodder for achieving the goals I mentioned above, and it should be a fun little project.

Tech

Here’s the some of the technology I’m using:

Current Status

The backend API is coded and running in Azure. I’ll share more detail about the API and how it’s built in future posts, including the overall architecture. I’ve been working on the mobile app for about a week now. I’m able to register/login through the mobile app and display my current alert definitions. Last week I put together some UI wireframes for the Create Alert Definition screens, and I’ll be working on implementing those screens this week.

Wrapping Up

In the spirit of working in public, I’ve made the Stock Alerts repository public: https://github.com/jonblankenship/stock-alerts. As with most projects, there are areas of the codebase that need some work and refinement, but we’ll address those things together down the road.

Thanks for reading! Until next time,

-Jon

(* After spending several months working on Open Shippers, I was burned out on it by the time I launched it in preview in February. I failed to differentiate it from other similar services out there, and I didn’t have any gas left in the tank to work on building an audience and making it successful. Someday I may do a post-mortem on the project. Open Shippers wasn’t a total failure though – I learned quite a bit while working on it, particularly about ASP.NET Core and Blazor, and I’ve reused several things I developed for Open Shippers in more recent projects. The site is still live, and I may revive efforts around it at some point, but I’m content to work on something else for the time being.)


If you’d like to receive new posts via e-mail, consider joining the newsletter.

Side Project

It’s been awhile since I’ve done any serious side-project work.  I’ve not had the energy or time to work on a personal project since I started working for my current employer almost three years ago, and, honestly, I haven’t felt much of a need.

When I joined my current employer three years ago, any side projects that I had in flight stopped dead in their tracks because – after years of consulting for the state – I was all of sudden working on interesting problems, being challenged daily, playing with cool new technologies, and building something new and innovative.  The needs I had satisfied previously after hours working on side projects (i.e., the desires to create, innovate, and learn new things) were now being satisfied at work.

I’ve got a bit more free time these days, and while I’m still being challenged at work, I’ve been looking for a project that I can spend some free time on with a few goals in mind:

  • Sharpen my skills on familiar (to me) tech
  • Work on new problems
  • Create something neat (and perhaps profitable)
  • Learn some new (to me) tech when appropriate

I’ve got some ideas for my next project(s).  I’m not ready to reveal what they are yet, but here’s a peek at just a few of the things I intend to use/work with in the coming months:

  • Natural language processing
  • Machine learning
  • Azure Service Fabric
  • ASP.Net Core
  • Some sort of API management to support monetization
  • Xamarin.Forms to target iOS/Android/Windows

So why am I sharing this publicly?  A few reasons…

  1. I wish I would have kept a journal of projects that I’ve worked on in the past to serve as my own personal reference for problems I’ve encountered and lessons learned.  This will be that journal.
  2. Communicating what I’m working on helps to sharpen my thoughts and aid in my understanding and retention.
  3. Sharing my progress will help to keep me accountable when my motivation wanes or my progress slows.
  4. It may be helpful to someone out there.  I hope it is.

I will work on this as time and energy permits.  I hope to post somewhat regularly and frequently, but I make no promises.

That said, thank you for joining me on this ride!

– Jon