Automatically generate grocery list with Trello and AWS Lambda
I use Trello for all kinds of personal stuff, one of which is keeping track of recipes and grocery lists. After planning which meals to cook and buy groceries for, a lot of manual work goes into checking every recipe and adding the ingredients to the grocery shopping list. Manual stuff is tedious, so I automated it with AWS Lambda. Read on to find out how!
The Trello board
Info
Our Trello board is in Swedish, so the screenshots will be in Swedish as well.
We have a Trello board that contains a lot of recipes grouped into lists, such as Pasta Dishes, Soups & Stews, and so on. We also have a list of groceries that needs to be bought, so that we always have the shopping list available when shopping.
In the above picture, you can get a glimpse of the Trello board, with each card containing a picture of the dish as well as a link to the external site where the recipe can be found.
What I wanted to automate was the following:
- Add a button to each card, that when clicked, adds the recipe to the Recipes to buy list (named Recept att handla in my board).
- Add a button to the board, that when clicked, reads through the Recipes to buy list and adds the ingredients (and amount of each) to the Grocery Shopping List (named AUTO Handlingslista in my board).
Below you can see the completed automation in action:
Trello setup: Part 1
I started by adding two new lists to my board, one to hold recipes that should be bought, and one for the generated grocery shopping list.
I then proceeded to add a checklist to recipe cards. This checklist contains the ingredients required for a single serving of the recipe. For example, if a recipe requires one onion for four servings, I would add onion:0.25
. Here I had to be consistent between recipes so that the units used for ingredients would be the same across all recipes.
The unit for onion here is number of onions, while for pasta I use gram and for cooking cream I use deciliter.
For ingredients where I do not care about the unit and just need to make sure that I buy it if needed, such as cooking oil and certain spices, I set the amount needed to 0
.
With the checklist(s) completed, I went on and created a Card button in the Automation menu. When clicked, this button triggers an action that adds a new card to the recipes to buy list. The created card gets the following title ANTAL_PORTIONER:{cardidlong}:{cardname}
. The ANTAL_PORTIONER
(number of servings in Swedish) is a placeholder that needs to be changed to an actual number before generating the shopping list.
The cards now look like this:
Clicking the button creates a new card in the recipes to buy list, and I then edit the text ANTAL_PORTIONER
in the title to the number of servings I need to purchase.
I also needed to get an API key and token for the Trello API, as described here.
I also needed to fetch the IDs of both the recipes to buy list, the grocery shopping list, and the board itself. This was easiest done by creating a new card in each of the lists, clicking on them and then adding .json
to the end of the URL in the browser. From there I could then extract the idList
and idBoard
variables.
AWS part
This whole thing really started with me wanting to find a use case for the newly released function URLs of AWS Lambda. So I decided to go with FastAPI in a Lambda function (as I usually do).
Since the API should be reachable from Trello I decided to keep the function URL open to the public. To secure it, I added code to the Lambda function that validates the X-Api-Key
header in incoming requests.
Secrets
To not require hard-coded secrets in the Lambda function, I added the following parameters to the AWS Systems Manager Parameter Store:
/trellomat/api_key
: Trello API Key/trellomat/token
: Trello token/trellomat/board_id
: ID of the Trello board/trellomat/shopping_list_id
: ID of the grocery shopping list/trellomat/recipe_list_id
: ID of the recipes to buy list/trellomat/aws_api_key
: The API key that is required in theX-Api-Key
header
Lambda code
Folder structure
The code examples below are structured as follows:
requirements.txt
The Lambda function requires the following libraries.
__init__.py
The handler function is a FastAPI
application wrapped by a Mangum
adapter. The API includes a single route POST /generate
, that neither requires nor returns any payload.
Authorization is done with the X-Api-Key
header, which is validated by the auth
method. The valid key is fetched from AWS Systems Manager Parameter Store and cached between invocations.
utils.py
This is a simple file that sets up a logger and tracer using AWS Lambda Power Tools.
models.py
This is where I define my ingredients.
In the INGREDIENTS
dict, I specify ingredients their units as well as which category the ingredient is part of.
The Category
decides which label an ingredient gets, and it is also used for sorting the generated shopping list. The default values in the Ingredient
class are there to not break the API whenever an ingredient is added on the Trello side before adding it to the Lambda function itself.
trello.py
This is where the magic happens. First, all required information is fetched from AWS Systems Manager Parameter Store.
We then initialize a TrelloClient
from the py-trello library, as well as instantiate objects for the board and lists.
The generate
function then:
- Archives all existing cards in the grocery shopping list.
- For each card in the recipes to buy list (which has the format
{servings}:{recipe_card_id}:{recipe_name}
), it fetches the card with therecipe_card_id
. - On this card, it looks for the checklist named
Ingredienser
. - For each checklist item, it adds the required ingredient amount to the
ingredients
dict. It also adds the ingredient unit and category from the model defined earlier. - The
ingredients
dict is then sorted by category. - For each ingredient in the
ingredients
dict, it creates a new card in the grocery shopping list.
template.yml
I deployed the Lambda function with AWS SAM. The SAM template looks like the following:
Trello setup: Part 2
With the API complete, I created a new Board button in the Automation menu. When clicked, a post request is sent to the Lambda function URL, with the API key specified in the X-Api-Key
header. The Lambda function then reads the recipes to buy list and generates a grocery shopping list.
Final result
Lo and behold, the final result! After adding a few recipes to the recipes to buy list, I can now automatically generate a grocery shopping list.