英文:
Pagination with Lever API in Google Apps Script
问题
我不了解JavaScript,对Google Apps Script的经验有限,但我需要将Google表格连接到我的公司的Lever ATS,通过Lever Requisitions API。经过多次尝试,我设法说服ChatGPT帮助我编写一个可以正常工作的脚本,但它未解决分页问题,因此我只能获得50行数据。ChatGPT在处理分页方面没有什么用,部分原因是脚本过长,目前包括四个函数:
- 一个
formatDate
函数,将日期值转换为 yyyy-MM-dd hh-mm-ss 日期时间格式。 - 一个
getColumnIndex
函数,返回数组中每个标题值的列索引。 fetchLeverRequisitions
函数是脚本的主要函数,实际上返回数据。getUserById
函数,将某些值从ID号转换为用户名。
我认为这些辅助函数都没问题,问题出在 fetchLeverRequisitions
函数上。我尝试添加了一个 do...while
循环来处理分页,但没有用,我得到的只是一行标题,没有附加数据。
这可能与其中一个标题有关 - customFields
,与其他标题不同,它是一个包含多个值的对象,需要将这些值解析为自己的标题,并且需要与其他日期值的格式化分开进行。
这些 customFields
标题包含在 columnHeaders
数组中,由customFields
后面的所有内容组成。
我的最新尝试如下,如果我需要在此处添加更多内容或进行进一步编辑以符合社区标准,请告诉我 - 我很乐意进行任何必要的编辑。
Lever API 文档在这里:https://hire.lever.co/developer/documentation。
以下是代码,已删除API密钥。它成功返回所有标题,但没有给我任何数据。
英文:
I do not know JavaScript and have limited experience with Google Apps Script, but I need to connect a Google Sheet to my company's Lever ATS through the Lever Requisitions API. After a lot of trial and error, I managed to coax ChatGPT to help me write a functioning script, however it fails to address pagination, so I only get 50 lines of data. ChatGPT has been pretty useless with pagination, partly because of the length of the script, which currently consists of four functions:
- a
formatDate
function to convert date values to yyyy-MM-dd hh-mm-ss datetime format - a
getColumnIndex
function which returns the column index for each value in an array of headers - the
fetchLeverRequisitions
function which is the main function of the script and actually returns data getUserById
function which converts certain values from ID numbers into user names.
I think the minor functions are all fine, it's the fetchLeverRequisitions
function that's giving me issues. I've tried to add in a do...while
loop to address pagination, but to no use - instead all I get is a row of headers with no additional data.
It may have something to do with one of the headers - customFields
, which unlike every other header is an object that contains multiple values which need to be parsed out as headers in their own right, and need to have their own date formatting performed separate from that of other date values.
These customFields
headers are contained in columnHeaders
array, and consist of everything that follows customFields
in the array.
My latest attempt is below, and if I need to add more here or make further edits to be in line with community standards, please just let me know - happy to make whatever edits needed.
Lever API documentation is here: https://hire.lever.co/developer/documentation
Code is below, with the API key removed. It successfully returns all headers, but doesn't give me any data.
function formatDate(date) {
var formattedDate = "";
if (date) {
var timestamp = new Date(date);
var year = timestamp.getFullYear();
var month = ("0" + (timestamp.getMonth() + 1)).slice(-2);
var day = ("0" + timestamp.getDate()).slice(-2);
var hours = ("0" + timestamp.getHours()).slice(-2);
var minutes = ("0" + timestamp.getMinutes()).slice(-2);
var seconds = ("0" + timestamp.getSeconds()).slice(-2);
formattedDate = year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
}
return formattedDate;
}
// Define the column headers
var columnHeaders = [
"id",
"name",
"requisitionCode",
"headcountTotal",
"headcountHired",
"backfill",
"status",
"team",
"location",
"hiringManager",
"owner",
"createdAt",
"updatedAt",
"closedAt",
"internalNotes",
"reqtype",
"customFields",
"contract",
"reqstart",
"reqtrigger",
"trigdate",
"reqassign1",
"assigndate1",
"reqassign2",
"assigndate2",
"reqassign3",
"assigndate3",
"result",
"resultdate",
"hireOwner",
"newstart",
"origin",
"source",
"exit",
"notice",
"departname",
"newname",
"tech"
];
// Get the column index based on the column header
function getColumnIndex(columnHeader) {
for (var i = 0; i < columnHeaders.length; i++) {
if (columnHeaders[i].toLowerCase().replace(/ /g, "") === columnHeader) {
return i;
}
}
return -1;
}
function fetchLeverRequisitions() {
const leverAPIKey = "**************";
const endpoint = "https://api.lever.co/v1/requisitions";
const pageSize = 100;
var offset = 0;
var allRequisitions = [];
var requisitions;
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(leverAPIKey),
"Accept": "application/json"
};
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheet.clearContents(); // Clear existing data
// Write column headers to the sheet
for (var i = 0; i < columnHeaders.length; i++) {
sheet.getRange(1, i + 1).setValue(columnHeaders[i]);
}
do {
var pageEndpoint = endpoint + "?limit=" + pageSize + "&offset=" + offset;
const response = UrlFetchApp.fetch(pageEndpoint, options);
if (response.getResponseCode() === 200) {
const responseData = JSON.parse(response.getContentText());
requisitions = responseData.data; // Assign the fetched requisitions
if (requisitions.length > 0) {
allRequisitions = allRequisitions.concat(requisitions);
offset += pageSize;
} else {
break; // No more requisitions to fetch
}
} else {
Logger.log("Failed to retrieve requisitions from Lever API. Response code: " + response.getResponseCode());
break;
}
} while (true);
// Write requisition data to the sheet
for (var i = 0; i < allRequisitions.length; i++) {
var requisition = allRequisitions[i];
for (var j = 0; j < columnHeaders.length; j++) {
var columnHeader = columnHeaders[j];
var value;
if (columnHeader === "customFields") {
var customFields = requisition[columnHeader];
if (customFields) {
for (var field in customFields) {
var customFieldHeader = field.toLowerCase().replace(/ /g, "");
var fieldValue = customFields[field];
var customFieldIndex = getColumnIndex(customFieldHeader);
if (customFieldIndex !== -1) {
if (fieldValue instanceof Date) {
value = formatDate(fieldValue);
} else {
value = fieldValue;
}
sheet.getRange(i + 2, customFieldIndex + 1).setValue(value);
}
}
}
} else if (columnHeader === "createdAt" || columnHeader === "updatedAt" || columnHeader === "closedAt") {
value = formatDate(requisition[columnHeader]);
sheet.getRange(i + 2, j + 1).setValue(value);
} else if (columnHeader === "reqstart" || columnHeader === "trigdate" || columnHeader === "assigndate1" || columnHeader === "assigndate2" || columnHeader === "assigndate3" || columnHeader === "resultdate" || columnHeader === "newstart") {
var customFieldHeader = columnHeader.toLowerCase().replace(/ /g, "");
var customFieldIndex = getColumnIndex(customFieldHeader);
if (customFieldIndex !== -1) {
value = formatDate(requisition["customFields"][customFieldHeader]);
sheet.getRange(i + 2, customFieldIndex + 1).setValue(value);
}
} else if (columnHeader === "hiringManager" || columnHeader === "owner") {
value = getUserById(requisition[columnHeader]);
sheet.getRange(i + 2, j + 1).setValue(value);
} else {
value = requisition[columnHeader];
sheet.getRange(i + 2, j + 1).setValue(value);
}
}
}
}
function getUserById(userId) {
const leverAPIKey = "**************";
const userEndpoint = "https://api.lever.co/v1/users/" + userId;
const headers = {
"Authorization": "Basic " + Utilities.base64Encode(leverAPIKey),
"Accept": "application/json"
};
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch(userEndpoint, options);
if (response.getResponseCode() === 200) {
var responseData = JSON.parse(response.getContentText());
return responseData.data.name; // Access the name property
} else {
Logger.log("Failed to retrieve user data for user with ID: " + userId);
return null;
}
}
答案1
得分: 0
提醒:本回答旨在为您的项目提供起点或参考信息。请注意,社区成员不提供编程服务。
根据您的问题,不管您对“customFields”头部的猜测如何,我理解您的主要问题是在fetchLeverRequisitions
函数的分页处理方面。您无法迭代到返回的API JSON结果的下一页。
虽然不是Lever API的专家,但在查看Lever开发者文档的分页部分时,您需要使用参数“offset”来在另一个API请求中检索下一页。这个“offset”是一个令牌值。
要解决这个问题,您可能需要重新编写您的脚本并尝试以下步骤:
- 捕获来自API调用的第一组结果数据。
- 从响应中获取令牌值和“hasNext”值。
- 如果“hasNext”值为true,请继续下一步。
- 发出新的API请求,这次包括
offset
参数,其值来自当前结果(offset
令牌值)。 - 重复第2步以获取新结果。
- 如果当前结果的“hasNext”值为true,请重复第4步。
- 如果当前结果的“hasNext”值为false,请结束“do-while”循环。
示例 fetchLeverRequisitions
调整后的脚本
const leverAPIKey = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■";
function fetchLeverRequisitions() {
var initialResult = initialAPICall();
var has_next = initialResult.hasNext;
var next_offset_token = initialResult.next;
var count = 1; // 用于可读性的页面计数
// 获取第一批数据
// 用于审查的示例控制台日志
console.log(`Page #1 viewed with ${initialResult.data.length} number of data.\nSample first data ID: ${initialResult.data[0].id}`);
do {
var current_data = loopedAPICall(next_offset_token);
count = count + 1;
// 获取下一批数据
// 用于审查的示例控制台日志
console.log(`Page #${count} viewed with ${current_data.data.length} number of data.\nSample first data ID: ${current_data.data[0].id}`);
has_next = current_data.hasNext;
next_offset_token = current_data.next;
} while (has_next)
}
// 运行API结果的第一页
function initialAPICall() {
var url = 'https://api.lever.co/v1/requisitions?offset=';
var headers = {
'Authorization': `Basic ${Utilities.base64Encode(leverAPIKey)}`,
"Accept": "application/json"
};
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var request = UrlFetchApp.fetch(url, options);
var response = JSON.parse(request.getContentText());
return { 'hasNext': response.hasNext, 'next': response.next, 'data': response.data };
}
// 在do while循环中运行,通过'offset'令牌参数直到最后一页
function loopedAPICall(offsetToken) {
var url = 'https://api.lever.co/v1/requisitions?offset=' + offsetToken;
var headers = {
'Authorization': `Basic ${Utilities.base64Encode(leverAPIKey)}`,
"Accept": "application/json"
};
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var request = UrlFetchApp.fetch(url, options);
var response = JSON.parse(request.getContentText());
return { 'hasNext': response.hasNext, 'next': response.next, 'data': response.data };
}
希望这有助于您解决通过API JSON结果的页面迭代问题。如果您认为自己的问题被误解,请更新您的问题并包括您的数据示例和期望结果。
英文:
Suggestion
> NOTE: This answer is intended to serve as a starting point or reference for your project. It's important to note that the community members do not provide coding services.
Based on your question, regardless of your hunch about the customFields
headers, I understand that your main problem is with your fetchLeverRequisitions
function's pagination handling. You cannot iterate to the next page of the returned API JSON result.
Not an expert in the Lever API, however when reviewing the Lever Developer documentation for Pagination, you need to use the parameter "offset" to retrieve the next page in another API request. This "offset" is a token value.
To address this issue, you may need to refactor your script and try these steps:
- Capture the first set of result data from your API call.
- Retrieve the token value and "hasNext" value from the response.
- If the "hasNext" value is true, proceed to the next step.
- Make a new API request, this time including the
offset
parameter with the value obtained from the current result (offset
token value). - Repeat step 2 for the new result.
- If the "hasNext" value of the current result is true, repeat step 4.
- If the "hasNext" value of the current result is false, end the "do-while" loop.
Sample fetchLeverRequisitions
Tweaked Script
const leverAPIKey = "■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■";
function fetchLeverRequisitions() {
var initialResult = initialAPICall();
var has_next = initialResult.hasNext;
var next_offset_token = initialResult.next;
var count = 1; //To count pages number for readability
//Get first data
//Sample console log for review
console.log(`Page #1 viewed with ${initialResult.data.length} number of data.\nSample first data ID: ${initialResult.data[0].id}`);
//console.log(initialResult);
do {
var current_data = loopedAPICall(next_offset_token);
count = count + 1;
//Get next data
//Sample console log for review
console.log(`Page #${count} viewed with ${current_data.data.length} number of data.\nSample first data ID: ${current_data.data[0].id}`);
//console.log(current_data)
has_next = current_data.hasNext;
next_offset_token = current_data.next;
} while (has_next)
}
//This runs the first page of the API result
function initialAPICall() {
var url = 'https://api.lever.co/v1/requisitions?offset=';
var headers = {
'Authorization': `Basic ${Utilities.base64Encode(leverAPIKey)}`,
"Accept": "application/json"
};
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var request = UrlFetchApp.fetch(url, options);
var response = JSON.parse(request.getContentText());
return { 'hasNext': response.hasNext, 'next': response.next, 'data': response.data };
}
//This runs in the do while loop until the last page via 'offset' token parameter
function loopedAPICall(offsetToken) {
var url = 'https://api.lever.co/v1/requisitions?offset=' + offsetToken;
var headers = {
'Authorization': `Basic ${Utilities.base64Encode(leverAPIKey)}`,
"Accept": "application/json"
};
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var request = UrlFetchApp.fetch(url, options);
var response = JSON.parse(request.getContentText());
return { 'hasNext': response.hasNext, 'next': response.next, 'data': response.data };
}
I hope this helps you in resolving the issue with iterating through the pages of the API JSON result. If ever you think your question has been misinterpreted, please update your question and include examples of your data and desired results.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论