If you haven’t lived under a rock for the last 18 months you would know ‘Serverless’ is the new cool kid in town. Microsoft’s offer is called Azure Functions while Amazon calls it AWS Lambda.
I won’t go into the various pros and cons of a serverless application in this blog post. There have been various posts written about the nuances of serverless you can Google for. I recommend having a read of Martin Fowler’s post here.
I recently worked on a project at Readify that was a POC (proof of concept) mobile app in a team of 4 people. We used Ionic for the app and Azure Functions was chosen for implement the back end web API. We didn’t have a lot of surface area to expose through the API so spinning up an app service with a hosted ASP.NET WebApi project wasn’t deemed necessary. We decided to have the mobile app talk directly to the Azure Function API endpoints. We deliberated on using API Management but ultimately decided not to since it was a POC project with limited scope.
An serverless function needs to be very lightweight. We were very careful not to introduce unnecessary complexity.
The http request needed to go through a layer that handles authentication and another that handles CORS. In an ASP.Net WebAPI application this is handled through the OWIN pipeline. The Auth and CORS middleware inspects and handles the request appropriately and sets the HttpContext accordingly.
It’s a simple enough pattern to follow so we designed our middleware interface based on OWIN.
It’s a simple pattern that works like the russian Matryoshka dolls. Each middleware has the chance to create/augment the response and decide whether or not to call the next middleware. You get a chance to modify the response before and after invoking the next middleware in the pipeline.
We don’t have a HttpContext to work with like we do in WebApi so we rolled out our own.
IUser is just a ClaimsPrincipal. We could have set the Thread.CurrentPrincipal as well but .NET core doesn’t seem to set it anyway in WebAPI. So why bother right? So far so good.
Just for completeness sake here is the interface and implementation we used to create the pipeline.
We just Register() the middleware we want and call the ExecuteAsync() with the FunctionContext. Couldn’t be any more simpler right?
Let’s look at an example of how we would implement CORS using our middleware now. I’ve allowed any origin here by using *. Use an appropriate value that works for you. (The CORS feature pane in your Azure Function settings might need an entry with just a * as well. The online guidance for this isn’t very clear. We found that putting one entry with a * worked for us)
Here is an simple example of how you could do bearer token authentication using this middleware concept. We used JWT.NET to implement JWT bearer tokens authentication in our TokenValidator class. I won’t include that code here as it is out of scope. Leave a comment here or email me if you get stuck implementing it.
I agree it is a fair bit of boilerplate but hang in there with me. We will get more into this topic of boilerplate in my learnings section of this post.
Here is an example from an API call that returns the current odometer reading for a car based on a registration number in the JWT claims. Notice how we are assuming the Context.User will be populated? That’s because of the authentication middleware we used before. Is it all starting to make sense now?
This is how we wired it all up. The Ioc.Bootstrap() method doesn’t do anything fancy. It just creates the required middleware instances and the FunctionContext with Request and Logger attached. Just like with OWIN, the order of middleware matters. Note how we allow the OPTIONS http verb because we want it handled within the function logic in our CORS middleware. Leave a comment here if you get stuck and need assistance.
That is the million dollar question. After all we could have gone with ASP.NET WebApi and got most of the boilerplate out of the box. Yes I do mean IOC here as well.
We wanted to challenge ourselves to see if we could do this POC app using a pay for consumption model. AppService hosted WebApi doesn’t fit that mould entirely. Nor does Azure Api Management yet. This biggest issue with API Management though is that tooling isn’t there for developers to emulate it when running your azure function locally against the mobile/web app. For a project that has many API endpoints, there is no easy way to setup API management easily. (ie We can use Swashbuckle when using ASP.NET WebApi to get a swagger file and import in API management but no such feature exists for Azure Functions http triggers).
AWS Lambda supports hosting ASP.NET WebApi projects as a severless app. I haven’t used this feature before but we would have chosen that option if it were available for us in Azure Functions. It solves the problem of boilerplate. It’s also interesting to note that at the time of development of this app Azure Functions didn’t support .NET core but Lambda did.
Don’t be. We went with the approach of serverless consumption model first but ended up having to implement our own OWIN like middleware and do auth and CORS our selves. It didn’t add any significant startup or performance cost to the app but if the project boilerplate was any larger it could have.
Before you start to implement a web api using Azure Functions http triggers consider the following
For most of us this was the first time we built a mobile app paired with a serverless web api. I learned a lot about the capabilities of Azure Functions and areas where ASP.NET WebApi outshines it. Your mileage may vary but keep these considerations and experiences in your mind then next time you are presented with the opportunity to implement a web api using Azure Functions or AWS Lambda.
Thoughts? Comments? Please let me know below.
Author: Dasith Wijes, 13th March 2018
Originally posted at: Gossip Protocol