Here’s what this post will show you:
- ToDo Example in Azure Functions with TypeScript
- REST-style API endpoints
- Async Create, Read, Update, Delete (CRUD) methods for Azure Table Storage with Azure.Data.Tables
- A helper method for having a cleaner project structure
For this Function App I wanted to have all code related to a feature inside the same folder and limit the amount of duplicate code. That’s why I’m using just one single Azure Function to handle all four CRUD scenarios by evaluating the HTTP Verb (GET for Read, POST for Create, PUT for Update and DELETE for, well, Delete. This in combination with an optional id parameter on the route lets us handle everything else with TypeScript.
While all domain-specific code in one place is a nice thing, I don’t actually want everything inside a single method. So I built a little wrapper function to call the correct function based on the HTTP verb. These wrappers are a common construct to create a kind of middleware and are also a good place to inject services like the TableClient or to deal with exception handling, logging or authorization requirements.
Finally we create four Azure Functions that we pass to our helper method to handle the business logic of CRUD’ing our ToDo items. We’re using the rather new Azure.Data.Tables SDK which embraces the Promise-based (async/await) coding style and is much cleaner to work with in my opinion.
For the entity model I created an interface with a single name property. This is being wrapped with the TableEntity<ToDo> type expanding it with partitionKey and rowKey properties which are required by the Table Storage as the combined index. Using this construct will also give you the correct return types on your queries such as TableEntityResult<ToDo> which also includes the etag and timestamp columns.
Check out the full working source code on GitHub and let me know if you have any questions or suggestions on how to improve this.
- This code is not production ready and is missing validation & proper error handling.
- Do validate the HTTP body before inserting the payload in the DB (POST & PUT).
- Strongly consider to not directly return the TableEntity models if you ever want to change the database behind the scene without completely breaking your API. Especially if its a public-facing API this should not be exposed.