英文:
API returning one result instead of multiple 11ty/eleventy-fetch Promise.all call
问题
我有一个11ty项目(静态站点生成器),我正在获取属性数据,然后在Promise.all调用中使用这些数据来执行以下操作:
1)获取所有属性图像和
2)获取租赁申请链接
然后将它们添加到一个名为allData的数组中,用于我的页面。
图像调用正常工作,但租赁API调用不起作用。
我正在使用Promise.all中的i更改发送给租赁API的API体,并且从我的console.logs中似乎工作正常,但我收到的结果是每次调用都返回相同的租赁链接。
我觉得这可能与我调用fetch/使用Promise.all的顺序有关,因为如果我添加一个hello console log,我的标记为i的数组将先记录,然后是hello,然后是下一个例如body 1 hello,body 2 hello,等等,然后所有的tpResponses(URL)将连续记录...这似乎不对。我无法看到实际的请求是否已经发送,因为这是在构建时完成的,所以我有点困惑,但我猜测基于结果只发送了一个apibody。
我尝试使用.then处理fetch调用,但我认为我配置错误了。我需要使用.then处理fetch调用吗,还是需要使用Promise.all以外的其他方法,它将如何工作?
以下是代码。感谢您的任何帮助!
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;
英文:
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:
- fetch all property images and
- 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;
答案1
得分: 0
解决方案:设置持续时间:"0s"
对于任何尝试运行for循环或Promise.all的人进行更新
11ty Fetch根据URL缓存获取的数据。
如果您在11ty Fetch调用中将持续时间设置为超过"0s"的任何值,则除非距离上次调用已经过去一天或更长时间,否则所有后续获取相同URL的数据都不会运行。
let response3 = EleventyFetch(url3, {
duration: "1d",
type: "json",
fetchOptions: {
method: "post",
headers: {
accept: 'application/json',
'content-type': 'application/json',
'Authorization': "Bearer "+AuthKey
},
body: apibody3
}
})
所以我所需要做的就是将"1d"替换为"0s",然后Promise.all/for循环就可以工作了。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论