UPDATE: This post is not up to date anymore, so I’ve wrote a new one here for Azure Functions v4 with TypeScript:
Azure Functions in TypeScript: REST CRUD with Azure Table Storage
Using Azure Functions to provide an HTTP API for database access is probably one of the most common scenarios. However, there don’t seem to be many tutorials on how to actually do this. So here’s how you can build a nice little API to Create, Read, Update & Delete (CRUD) records from Azure Table Storage.
TLDR: If you just want to see the source code, head over to my GitHub repo!
We’ll be using NodeJS and Version 2 of the Azure Function Runtime which was officially released just a week ago:
Compared to functions created with v1, there are two distinct differences we have to be aware of.
First, there’s the
async keyword preceding the function which can easily be missed (as did I) but matters quite a bit. This means the function will autmatically notify the runtime once it has finished. You can read more about this here.
This leads us straight to the second change — there is no more call to
context.done() as it’s not required anymore. In fact, if you try to call it yourself inside the function you’ll get an error:
Less code to take care of — sounds good, right? Sure! But only until at some point your code returns while it still should be running…
That can happen to you when you are using the very common callback pattern for asynchronous code inside a function marked as
In this case we would never see any data returned from an async function as it would always return a 200 status code by default before the call to the database could even finish.
How do we fix this?
The easiest way for now is to just remove the
async keyword and go back to handling the call to
context.done() ourselves. We could also manually wrap the calls to the Azure SDK methods in Promises, but that’s a topic for another time.
But now, let’s get to some code!
> npm install -s azure-storage
> npm install -s uuid
Then we’ll create four different HTTP-triggered functions, one for each CRUD request. We could certainly do everything in one single function, but I personally prefer my functions nice and small, even if there’s some duplicate code.
function.json files we update the
methods field to reflect what we’re trying to do with each of them, so
- ItemCreate => POST
- ItemDelete => DELETE
- ItemRead => GET
- ItemUpdate => PUT
Afterwards we create a table inside our Storage Account. I recommend using the Azure Storage Explorer for these kind of things.
Lastly we’ll need to provide the database connection details for the Function App. Since it’s not a good practice to put any kind of credentials inside the code we can simply add the connection string to the Application settings using AZURE_STORAGE_CONNECTION_STRING as the key. The Azure Storage SDK will then automatically get this value when we create our TableService. For local debugging we can also add the connection string to the local.settings.json file.
Now lets have a look at the code.
To store an object in Azure Table Storage we’re gonna send it to the backend inside the body of a POST request. Depending on your partition strategy for the Table Storage we have to add PartionKey & RowKey properties to the object before we can store it in the database. I’ll be using a single static PartitionKey and a GUID for the RowKey to keep it simple for now.
We also should make sure the object is “flat”, so there are no nested properties as they can’t be stored in the table, but that’s not in the scope of this posts.
Here’s the complete Create-code with detailed comments:
Here we can either pass an ID as a parameter to get the desired object or we can just call the function without any further input and get the top 100 records from the database.
Updating a record is basically a simplified create since we already have the PartitonKey & RowKey set. You can also choose to merge two objects instead of replacing the one in the database.
When deleting a record we usually only require the ID. However, the Azure Storage SDK only takes an object for the
deleteEntity() method. The easiest way then is to create a new object only consisting of PartitionKey & RowKey to identify the record we want to delete.
And there we have it! Once again, here’s the link to the full code on GitHub.
Now, unfortunately this is not really a nice REST-style API yet, but hopefully we can look at that in a different article.
Here’s part 2 explaining how to turn this into a REST API.