Search code examples
javascripthtmlnode.jsjinja2nunjucks

Weird looping over bug in nunjucks


I have built a server in nodejs for a multiplayer snake game.

I am currently working on allowing users to create their own bots, and for this I must have a way to generate and store API keys.

I have this figured out. Here is a nice screenshot from AWS DynamoDB showing how the data is formatted.

item schema

The item we want to focus on is the api_keys row. Expanded, it is just a list of API keys [<key>,<key>,etc] Each api key is just a string that I generate with a helper function.

  function generateAPIKey() {
    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let apiKey = '';
  
    for (let i = 0; i < 32; i++) {
      const randomIndex = Math.floor(Math.random() * characters.length);
      apiKey += characters.charAt(randomIndex);
    }
  
    return apiKey;
  }

This all works fine. I then created a login and signup system-> this works fine too!

The problem came up when I tried to make a table of all the API keys for a dashboard. Here is how the dashboard is supposed to look.

enter image description here

Here is how I managed this one.

{% set api_keys =  ["45ZeHLkHLskSbRuBvLObUGZ3lfDSJTVZ","8DAefL5BtSwVOUAp0d1ZYrEEr0sliGBU","9XZLnqBwARSMEFv4O4PBtcxY4Lpob3x2","BKce7wVSnblYEfWv2pAXHlbyrCuPpxmn","BrCv6cHP6uFaohS11GnWIllvzB3VoX4K","CJlyot3evxeR6fgW98sTBblKmrzKaRYy","CsCvTrJrdscXqYoLHnoRBlLwpReNKEJT","IYaitmquR42MafZlpd6clsY9e8NMCcmL","LU06037xiU71ZZJcfgXCauvlTuGybM6N","MZU0aVmyCMcsc2qaVsk9OUXGBixy9zxQ","PapmjncSJYDcUtTaDuatgZwXyIwubiQ2","RH0GV1SqX1IUAL0Rx9MQrlaK3BrK61Mr","RJ3VkuYbp0Zxz2lwQdRGwyKmtpH1JyMY","RMUKYDi0lm0AmQIadaZRx3J6pNWlJ5k9","RvnLoV7vtgEBEhvsLDMVJKXFugcoXHoY","i9LtNKURTBV5R3JGZNnjWfhq0kJz8TgF","ju0ssxnrH3ZoBxhtKwtuFJuWpNAJzSo0","mWBWiIfdA6C3KRCMquGJC76u7WMTPPdE","nyhHKOqT2G2zX95I99MHXKzJLchYsqZb","o0seZ0nYXH021Cy5vTVtthaUqY9whwOp","x5Sj0pFYrK4CDoXAWIrZqhoCTUur3AXo"]  %}

This is just filling the api_keys variable with randomly generated api keys.

Then, I fill the rows with the following lines

{% for uid in api_keys %}
<tr class = "table-row" id="row-{{ loop.index0 }}">
   <td><b>{{ loop.index0 }}</b></td>
   <td class = "uid">{{ uid }}</td>
   <td class = "manage">
      <button class = "btn btn-inline">Copy Key</button>
      <button class = "btn btn-danger btn-inline">Delete</button>
   </td>
</tr>
{% endfor %}

and this works too!

The problem arises when I try to loop over the user data. If I switch from doing {% for uid in api_keys %} to {% for uid in user.api_keys %}, everything breaks.

No errors in the console, nothing on the server, but the rows dont print out. I just get an empty table.

I assumed that the error was that user.api_keys was an empty array, or something like that. So, I printed the variable just to check.

{{ user.api_keys | dump }}

enter image description here

Logs everything correctly! The loop just doesnt work when I use the user data instead of template data.

for reference, here is the full code on github

If anyone has the foggiest idea please help me out here. Everything looks correct, it just doesnt work!

Edit

I have been doing some more testing, and I found that just trying to log 1 element from the list (instead of using dump) returns nothing as well.

{{ user.api_keys[0] }}

is just empty, while

{{ api_keys[0 }} /* the pre filled template one */

displays the key properly


Solution

  • After some extensive testing

    I have found the bug.

    I assumed that dumping the content on the screen provided me with a clear view of what is going on.

    After logging the data to the console, you find something very different.

    enter image description here

    For those of you struggling to loop over data stored in AWS DynamoDB, notice that the data type is not an array. It is stored in a set. Access the actual values with .values

    Not sure if anyone else will have this problem because it's so specific. If any mods think so go ahead and delete the post, or comment that I should.