Recently I needed to write an Azure Function app that uses the Apache POI library for getting the text from Microsoft Word 94 documents (and yes, I am fully aware that the year is currently 2024, but some people still have 30 year old documents kicking around!).
Being somewhat allergic to coding in Java (this is a personal thing, if you like Java then good for you) I decided to try out writing the code using Kotlin from JetBrains instead. I’m already using IntelliJ as I work with Apache Spark using Scala, so the tooling was already there and ready to go for this.
Microsoft, unexpectedly, have an article about creating Azure Function apps using Kotlin, so this was a great start and, pretty quickly, I had a version of my function app ready to try out.
Debugging
This isn’t as straight forward as just running a debug configuration unfortunately, it would be nice if it was, but it’s honestly not too bad either. The Microsoft article talks about how to do it, and once you get into the habit of running the app and then running a configuration to attach the debugger, it just starts to flow.
So, running locally I have an Azure Function app, written in Kotlin, using the Apache POI library, extracting text from a Wore 94 document (it kills me a little bit every time I write that part). So I opened up HTTPie and started firing sample documents at it
It works great, so next I want to deploy this thing, and that’s where the smooth ride hits a few bumps.
Deployment
In the article it tells you to just run the azure-functions:deploy
Maven target. It somewhat skips over the fact that you should probably first open up the pom.xml
file and do things like change the resource group name, function app name, and the app region. These might seem trivial, but if you have issues with data leaving certain regions then they become really important.
So, first up, change the pom.xml
file, specifically these values in the properties
section.
- functionAppName
- functionAppRegion
- functionResourceGroup
Having done that I tried to run the maven target again and… failed.
But it failed because it was complaining that it couldn’t read the azureProfile.json
or accessTokens.json
files and that I should check that I’m logged in using the Azure CLI.
This is weird because I had just created the resource group and a few other things for my deployment using the CLI. But I logged in again and tried again and still the same error!
A bit of searching around the web and it turns out that the Azure CLI had been updated a while ago and changed how it was handling tokens, but the Maven Archtype hasn’t been updated to reflect this! So, what next?
Well, most deployments to Azure Functions work by packaging up the function app, producing a zip, and then pushing this up. There are other ways, but this works well and is pretty robust. But it’s all hidden away in the target, so how can we replicate what it does. We can do this fairly easily it turns out.
There are a few steps we want to follow.
- Clean everything up
- Package the app
- Create the zip
- Deploy the zip
Cleaning things up is easy, we can just run mvn clean
and we’re done.
Packaging we need to run a couple of things. First is the mvn package
target to build our application, and then the next is the mvn azure-functions:package
target which creates our directory structure that we need to be able to publish the app (this is the really important step).
Once both of these have been executed, if we look under the target
directory we can see a new azure-functions
directory which contains everything we need, all the jar
files, the host.json
file and more.
Now, we’re just creating a zip to deploy, so in the command line we move to the target/azure-functions/<function app name>
folder and run the following.
> zip -r ../../../deploy.zip *
That will create a deploy.zip
file in the root of the source directory with all the contents of the packaged function app directory within it.
Then, we publish the zip to our function app (you need to create that first by the way, as a Java 8 function app) with the following command.
> az functionapp deployment source config-zip -g <resource group name> -n <function app name> --src ./deploy.zip
And that’s it, the function app is deployed. You can then grab the URL from the Azure Portal and change the URL in HTTPie, send the document, and get the response.
What I ended up doing was putting all of the steps into a Makefile so I could just run make deploy
whenever I wanted to push a new version
clean:
mvn clean
package: clean
mvn package
mvn azure-functions:package
deploy: package
cd ./target/azure-functions/<app name>; zip -r ../../../deploy.zip *
az functionapp deployment source config-zip -g <resource group name> -n <func app name> --src ./deploy.zip
rm deploy.zip
Putting in the dependencies meant that I only needed to execute the deploy step, instead of remembering to clean and package as well.
Wrapping up
Pretty quickly I ended up with a function app deployed, written in Kotlin, which could read and extract text from Word 94 (sob sob sob) file. Other than working out the deployment process it went really smoothly and it runs incredibly well.
I’m probably not quite ready to give up C# and dotnet to use this for everything, but this is a nice option when a Java based solution is the better option.