javascriptnode.jsapi

API returning one result instead of multiple 11ty/eleventy-fetch Promise.all call


I've got an 11ty project (static site generator) where I'm fetching property data then using this data in a Promise.all call to:

  1. fetch all property images and
  2. fetch tenancy application urls

Then add these into one array labeled allData for my pages.

Image call is working fine but the tenancy api call is not. I'm changing the api body I'm sending to to the tenancy api by using the i from Promise.all and this seems to be working from my console.logs but the result I'm getting is the same tenancy link being returned for each call.

I feel like it might have something to do with the order I'm calling fetch/using Promise.all because if I add a hello console log my an array with i label will log followed by hello, then the next e.g. body 1 hello, body 2 hello, etc. and then all the tpResponses (urls) will log in a row.. which doesn't seem right. I can't see the actual requests going through since this is done in build time so I'm a little confused but I'm guessing only one apibody is being sent based on results.

I've tried using .then for the fetch calls but think I configured this wrong. Do I need to use .then for the fetch calls or something other than Promise.all and how would that work?

Code below. Any help would be appreciated!

require('dotenv').config();
const EleventyFetch = require("@11ty/eleventy-fetch");
const crypto = require('crypto');

async function getPropertyData(){
    console.log("getPropertyData...")
    //Property vars
    var username = process.env.MANOR_USERNAME;
    var password = process.env.MANOR_PASSWORD;
    var auth = 'Basic ' + Buffer.from(username + ':' + password).toString('base64');
    //Tenancy vars
    var api_public_key = process.env.TPS_KEY;
    var api_secret = process.env.TPS_SECRET
    let api_url = "https://www.tpsportal.co.nz/api/v1/tenancy_application/create_property"
    
    function sign(endpoint, key, secret, date, body) {
        const encoded = new
        Buffer([endpoint,body,date].join('\n')).toString('base64');
        return crypto
        .createHash('sha256')
        .update(encoded + '+' + secret, 'utf8')
        .digest()
        .toString('hex');
    }
    
   

    //Get Property Details
    const url = `https://api.getpalace.com/Service.svc/RestService/v2AvailableProperties/JSON`
    const response = EleventyFetch(url, {
        duration: "1d",
        type: "json",
        fetchOptions: {
            headers: {
                accept: 'application/json',
                'content-type': 'application/json',
                'Authorization': auth
            }
        }
    })
    const properties = await response;



    //Create URLs for Image call
    let propertyImageUrls = []
    properties.forEach(property => {
        propertyImageUrls.push(`https://api.getpalace.com/Service.svc/RestService/v2AvailablePropertyImagesURL/JSON/${property.PropertyCode}`)
    });
    


    let allData = [];
    
    //Fetch Property Images
    const allPropertyImages = await Promise.all(propertyImageUrls.map(async (url,i) => {
        const imageResponse = await EleventyFetch(url, {
            duration: "1d",
            type: "json",
            fetchOptions: {
                headers: {
                    accept: 'application/json',
                    'content-type': 'application/json',
                    'Authorization': auth
                }
            }
        });
        let tpData;
        const imageData = await imageResponse;
        //Add property matching details + image to allData array

        let apibody = JSON.stringify({
            client_code: "8754",
            property_code: properties[i].PropertyCode,
            agent_name: properties[i].PropertyAgent.PropertyAgentFullName,
            agent_email: properties[i].PropertyAgent.PropertyAgentEmail1,
            unit: properties[i].PropertyUnit,
            street_number: properties[i].PropertyAddress1,
            street_name: properties[i].PropertyAddress2,
            suburb: properties[i].PropertyAddress3,
            city: properties[i].PropertyAddress4,
            postcode: properties[i].PropertyFeatures.PropertyPostCode
        })
        console.log("API BODY " + i +" :",apibody)
        var api_date = new Date().toISOString();
        var signature = sign(api_url,api_public_key,api_secret,api_date,apibody) 
        console.log('hello')
        let tpResponse = await EleventyFetch(api_url, {
            duration: "1d",
            type: "json",
            fetchOptions: {
                method: 'post', 
                headers: {
                    accept: 'application/json',
                    'content-type': 'application/json',
                    'X-API-DATE': api_date,
                    'X-API-KEY': api_public_key,
                    'X-API-SIGNATURE': signature
                },
                body: apibody
            }
        })
        console.log("tpResponse: ", apibody)
        tpData = await tpResponse;
        console.log("tpData: ", tpData)

This is the error: tpData is just giving me the same link for each property instead of different links

        allData.push([properties[i], imageData, tpData])
    }))
    
    // console.log(allData)
    return allData;
}

module.exports = getPropertyData;

Solution

  • Solution: set duration: "0s"

    Update for anyone trying to run for loops or Promise.all

    11ty Fetch caches fetch data based on the url.

    If you have duration set to anything over "0s" in your 11ty Fetch call all following fetch data to the same url won't run unless it's a been a day or longer since last call.

    let response3 = EleventyFetch(url3, {
                duration: "1d",
                type: "json",
                fetchOptions: {
                    method: "post",
                    headers: {
                        accept: 'application/json',
                        'content-type': 'application/json',
                        'Authorization': "Bearer "+AuthKey
                    },
                    body: apibody3
                }
            })
    

    So all I had to do was replace "1d" with "0s" and Promise.all/for loops work.