On today’s post we will be creating our Serverless REST API with Azure Functions. We will be doing that with Visual Studio.
This post is part of a series where the first part should be read beforehand.
Creating the “basic MM Service”
For this we have to install the latest Azure Functions Tools and an operative Azure Subscription. We can do this from Visual Studio, from either “Tools” and then “Extensions and Updates”, we should either install or update the latest “Azure Functions and Web Jobs Tools” (if we are using VS 2017) or if we are in VS2019, we should go to Tools, then “Get Tools and Features” and install the “Azure development” workload.
We should create a new “Azure Functions” template based Project.
And select the following options:
- Azure Functions v2 (.NET Core)
- Http trigger
- Storage Account: Storage Emulator
- Authorization level: Anonymous
Then we can click create and just run it to see it working. Pressing F5 should start the Azure Functions Core Tools which enables us to test our functions locally, a convenient feature I’d say. Once starting we should see a console window with the cool Azure Functions logo flashing.
then once the startup has finished copy the function URL, which in our case is “http://localhost:7071/api/Function1”.
To try this from a client perspective we can use a browser and type “http://localhost:7071/api/Function1?name= we are going to build something better than this…” but I’d rather use a serious tool like Postman and issue a GET request with a query parameter with key “name” and the Value “we are going to build something better than this…”. This should work right away and also some tracing should appear on the Azure Functions Core Tools. The outcome in Postman should look like:
Or if you opted for the browser test “Hello, we are going to build something better than this…” – which we are going to do in short.
We just saw a “Mickey Mouse” implementation but if you are like me, that won’t satisfy you unless you add some layers in to decouple responsibility and some interfaces because, er… we like complication right? 😉 – Not really but I thought it would be good to put in code which does something simple but is still as SOLID as I can get without too much effort.
What are we going to build?
We are going to create a REST API that exposes a simple list of categories (a complex POCO with Id and Name), then the API Controller which will be the main API interface and it will delegate obtaining the Data to a Service and the Service to a Repository.
And we will stop here, so this will be completely on memory so no Database will be hurt in the process, also no Unit Of Work will Need to be implemented as well.
We will create some interfaces and configure/register them with Dependency Injection, which uses the ASP.NET Core DI basically.
I have a disclaimer which is that WordPress has somehow disabled HTLM editing so I can’t put code from GIT or have a nice “code view” in place which is… making me think of switching to another blog provider… so if you have any suggestion, I’d appreciate you mention it to me with a comment or directly.
Creating the “boilerplate”
We will start by creating the POCO (Plain Old CLR Object) class, Category. For this we can create a “Domain” Folder and inside it create a “Models” Folder where we will place this class:
public class Category { public int Id { get; set; } public string Name { get; set; } }
public interface ICategoryRepository { Task<IEnumerable<Category>> ListAsync(); Task AddCategory(Category c); Task<Category> GetCategoryById(int id); Task RemoveCategory(int id); Task UpdateCategory(Category c); }
public class CategoryRepository : ICategoryRepository { private static List<Category> _categories; public static List<Category> Categories { get { if (_categories is null) { _categories = InitializeCategories(); } return _categories; } set { _categories = value; } } public async Task<IEnumerable<Category>> ListAsync() { return Categories; } public async Task AddCategory(Category c) { Categories.Add(c); } public async Task<Category> GetCategoryById(int id) { var cat = Categories.FirstOrDefault(t => t.Id == Convert.ToInt32(id)); return cat; } public async Task UpdateCategory(Category c) { await this.RemoveCategory(c.Id); Categories.Add(c); } public async Task RemoveCategory(int id) { var cat = _categories.FirstOrDefault(t => t.Id == Convert.ToInt32(id)); Categories.Remove(cat); } private static List<Category> InitializeCategories() { var _categories = new List<Category>(); Random r = new Random(); for (int i = 0; i < 25; i++) { Category s = new Category() { Id = i, Name = "Category_name_" + i.ToString() }; _categories.Add(s); } return _categories; } }
public interface ICategoryService { Task<IEnumerable<Category>> ListAsync(); Task AddCategory(Category c); Task<Category> GetCategoryById(int id); Task RemoveCategory(int id); Task UpdateCategory(Category c); }
public class CategoryService : ICategoryService { private readonly ICategoryRepository _categoryRepository; public CategoryService(ICategoryRepository categoryRepository) { _categoryRepository = categoryRepository; } public async Task<IEnumerable<Category>> ListAsync() { return await _categoryRepository.ListAsync(); } public async Task AddCategory(Category c) { await _categoryRepository.AddCategory(c); } public async Task<Category> GetCategoryById(int id) { return await _categoryRepository.GetCategoryById(id); } public async Task UpdateCategory(Category c) { await _categoryRepository.UpdateCategory(c); } public async Task RemoveCategory(int id) { await _categoryRepository.RemoveCategory(id); } }
Adding the necessary services wiring up
This is where everything comes together. There are some changes though, due to the fact that we will be adding dependency injection to setup the services. Basically we are following the steps from the official Microsoft how-to guide which in short are:
1. Add the following NuGet packages:
- Microsoft.Azure.Functions.Extensions
- Microsoft.NET.Sdk.Functions version 1.0.28 or later (at the moment of writing this, it was 1.0.29).
2. Register the services.
For this we have to add a Startup method to configure and add components to an IFUnctionsHostBuilder instance. For this to work we have to add a FunctionsStartup assembly attributethat specifies the type name used during startup.
On this class we should override the Configure method which has the IFUnctionsHostBuilder as a parameter and use this to configure the services.
For this we will create a c# class named Startup and put the following code:
[assembly: FunctionsStartup(typeof(ZuhlkeServerlessApp01.Startup))] namespace ZuhlkeServerlessApp { public class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { builder.Services.AddSingleton<ICategoryService, CategoryService>(); builder.Services.AddSingleton<ICategoryRepository, CategoryRepository>(); } } }
Now we can use constructor injection to make our dependencies available to another class. For example the REST API which is implemented as an HTTP Trigger Azure Function will resolve the ICategoryServer on its Constructor.
For this to happen we will have to change how this HTTP Trigger is originally built (hint: It’s Static…) so we need it to call its constructor..
We will remove the Static part on the generated HTTP Trigger function and the class that contains it or either generate a complete new file.
We will either edit it or add a new one with the name “CategoriesController”. It should look like follows:
public class CategoriesController { private readonly ICategoryService _categoryService; public CategoriesController(ICategoryService categoryService) //, IHttpClientFactory httpClientFactory { _categoryService = categoryService; } ..
The dependencies will be resolved and registered at the application startup and resolved through the constructor each time a concrete Azure Function is called as its containing class will now we invoked due it is no longer static.
So, we cannot use Static functions if we want the benefits of dependency injection, IMHO a fair trade off.
In the code I am using DI on two places, one on the CategoriesController and another on an earlier class already shown, the CategoriesController. Did you realize the constructor injection?
Creating the REST API
Now we are ready to finish implementing the final part of the REST API… Here we will implement the following:
- Get all the Categories (GET)
- Create a new Category (POST)
- Get a Category by ID (GET)
- Delete a Category (DELETE)
- Update a Category (PUT)
Get all the Categories
[FunctionName("MMAPI_GetCategories")] public async Task<IActionResult> GetCategories( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "categories")] HttpRequest req, ILogger log) { log.LogInformation("Getting categories from the service"); var categories = await _categoryService.ListAsync(); return new OkObjectResult(categories); }
Create a new Category
[FunctionName("MMAPI_CreateCategory")] public async Task<IActionResult> CreateCategory( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "categories")] HttpRequest req, ILogger log) { log.LogInformation("Creating a new Category"); string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); dynamic data = JsonConvert.DeserializeObject<Category>(requestBody); var TempCategory = (Category)data; await _categoryService.AddCategory(TempCategory); return new OkObjectResult(TempCategory); }
This will use the POST HTTP verb, has the same route and will expect the body of the request to contain the Category as JSON.
Our code will get the body and deserialize it – I am using the Newtonsoft Json library for this and I delegate to our Service interface the Task to add this new Category.
Then we return the object to the caller with an OkObjectResult.
Get a Category by ID
The code is as follows, using a GET HTTP verb and a custom route that will include the ID:
[FunctionName("MMAPI_GetCategoryById")] public async Task<IActionResult> GetCategoryById( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "categories/{id}")]HttpRequest req, ILogger log, string id) { var categ = await _categoryService.GetCategoryById(Convert.ToInt32(id)); if (categ == null) { return new NotFoundResult(); } return new OkObjectResult(categ); }
To get a concrete Category by an ID, we have to adjust our route to include the ID, which we retrieve and hand over to the categoryservice class to recover it.
Then if found we return our already well known OkObjectResult with it or, if the Service is not able to find it, we will return a NotFoundResult.
Delete a Category
[FunctionName("MMAPI_DeleteCategory")] public async Task<IActionResult> DeleteCategory( [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "categories/{id}")]HttpRequest req, ILogger log, string id) { var OldCategory = _categoryService.GetCategoryById(Convert.ToInt32(id)); if (OldCategory == null) { return new NotFoundResult(); } await _categoryService.RemoveCategory(Convert.ToInt32(id)); return new OkResult(); }
Update a Category (PUT)
The Update process is similar as well to the delete with some changes, Code is as follows:
[FunctionName("MMAPI_UpdateCategory")] public async Task<IActionResult> UpdateCategory( [HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "categories/{id}")]HttpRequest req, ILogger log, string id) { var OldCategory = await _categoryService.GetCategoryById(Convert.ToInt32(id)); if (OldCategory == null) { return new NotFoundResult(); } string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var updatedCategory = JsonConvert.DeserializeObject<Category>(requestBody); await _categoryService.UpdateCategory(updatedCategory); return new OkObjectResult(updatedCategory); }
Here we use the PUT HTTP Verb, receive an ID that indicates us the category we want to update and in the body, just as with the Creation of a new category, we have the Category in JSON.
We check that the Category exists and then we deserialize the body into a Category and delegate to the service Updating it.
Finally, we return the OkObjectResult containing the updated category.
Deploying the REST API



Checking our Azure REST API




Next..
And that’s it for today, on our next entry we will jump into API Management .