Running Serverless Apollo GraphQL on AzureFunctions with cheap Azure Blob Table database(s)
Merry Christmas holidays and happy new years.
This is a bit of a holiday reading, I wanted to start by give you the sense of what I’ve been tinkering as an experiment, and it looks increasingly like this is going into production before 2019 ends.
Plan
Have
I have a bunch of Azure storage Tables (about 70k rows of cheap database - at $1 / month storage) - they are spread out across several containers but for the basic purposes - I think of them as independent tables that lack proper relationships defined between them.
I think that’s appropriate to describe most no-sql databases.Azure Functions based CRUD REST APIs wraps around the Azure Blob Table - problem - no good caching or relationship mechanism. I wasn’t a big fan of keep rolling out CRUD REST endpoints, feeling that I should try find a different way.
Idea
Run a GraphQL server on Azure Functions
Learn:
If you want to run GraphQL on Azure Functions - there’s a dotnet way and there’s a NodeJS way
The dotnet version
https://www.tpeczek.com/2019/05/serverless-graphql-with-azure-functions.html
https://medium.com/@seekdavidlee/eklee-azure-functions-graphql-a-serverless-graphql-implementation-on-azure-484611c3680b
I’ve personally made a stack decision to stick to NodeJS/TypeScript/JavaScript, so I won’t be exploring the dotnet server.
The NodeJS version
A quick look around will send you to Apollo Server which has done 3 videos with Microsoft Azure/Channel9 on getting started, running on AppService, and running on Azure Functions (on consumption).
Part 1 https://www.youtube.com/watch?v=7R33hGFV4f0
Part 2 https://www.youtube.com/watch?v=Mt4bBpOdwyE
Part 3 https://www.youtube.com/watch?v=unUeFApHeT0
Write
Steps after Apollo + AzureFunctions 3-part videos.
Resolving GraphQL entities to Azure Blob Table
Resolving Relationships
Securing with Azure AD
Deploying to AzureFunctions
Reroute via Azure Function proxy
Future
Switch to Apollo RESTDataSource
Apollo Client with Angular and Observable bindings
Apollo Server with Redis cache
Learn
After the three videos, particularly the first and the third - to understand GraphQL server, and hosting it on AzureFunctions, you’ll end up with a working graphql server running on localhost showing you books array from memory. Getting here after watching three videos was extremely fast ~30minutes. Very surprising how much shortcut we took to get here this fast.
A really fancy thing Apollo did was to put the graphql endpoint on POST, and run the playground test environment on GET. Pointing a browser to the same endpoint will show the playground.
Here is the playground running the sample books query. Debug works wonderfully running in localhost.
By default, the playground will do continuous polling on the endpoint. That’s going to keep the Function awake and incur a lot of costs. It might also keep bumping into any local debug breakpoints. So let’s turn that off. I also set debug to false.
Write - Resolving Azure Table
Next, we need to extend from here. My original AzureFunctions has REST endpoints that calls Azure storage Tables via the Azure.Storage SDK. So bring those in.
And start to switch out the code
Notes: Azure.Storage does old style callbacks, so I’m wrapping them in a Promise that I can resolve. When I resolve - I want the raw JSON from the service, not the ‘tweaked’ JSON in result (it does weird things to your JSON entities, that’s a blog for another time).
A really nice thing about Apollo Server resolve function is that it knows how to handle promises naturally. So this tweak basically is me saying - hey, go fetch from Azure Storage Table from the ‘flows’ container.
To run this locally, we’ll need to store an Azure storage key in local.settings.json
We can reference this like so:
Write - Resolving relationships
Notes:
I call “ref_” because I’m terrible at making property names. Lots of fields like “environmentName” or “environment” are already taken. It got too hard picking new names, I decided to call all entity references ref_
Deploy to Azure Functions
Need to deploy two parts:
Friends don’t let friends right click to deploy unless another friend put it in the right click menu. In that case, please don’t make me choose my friends.
Also, right click and upload local settings file to send our MyStore setting into Azure functions.
That’s two right clicks and deployment done!
Connect Azure Function proxy
My existing API routes are already covered with Azure Functions proxy. So I added a new route that takes graphql over to this separate Azure Functions. I also bury the functionkey in the route so users can’t see it.
Future
There’s a bunch more ideas for the future.
Explore federated authentication and user level security.
Figure out why Azure Storage SDK next generation doesn’t do Tables
Switch from using SDK to Azure Storage REST and use Apollo’s excellent RESTDataSource implementation instead (it already implemented HTTP caching, pagination, top, etc)
implement mutations, especially e-tag handling.
implement server side Redis cache
Implement Apollo Client to fetch data for my existing Angular front-end
Implement client side cache and observable pattern
Let me know if you find this interesting and want to follow along. I wrote this mostly as documentation for what I’m doing and the incremental changes I’m making as I go.