I am trying to make a recursive function that returns all the subblocks of a given block.
For some background information, I am using the Notion API to get all the blocks from a page. A block can have a children of blocks, and those child blocks can also have a children of blocks. That is why I need a recursive function to check for all blocks.
Actually, I have already successfully made a recursive function from google appscript, as below
// recursive function to get all nested blocks in a flattened array format
function getSubBlocks(blockId) {
const url = `https://api.notion.com/v1/blocks/${blockId}/children?page_size=100`
let options = {
"async": true,
"crossDomain": true,
"method": "get",
"headers": {
"Authorization": `Bearer ${NOTION_API_KEY}`,
"Notion-Version": "2022-02-22",
"Content-Type": "application/json"
}
};
var response = JSON.parse(UrlFetchApp.fetch(url, options).getContentText());;
console.log(response)
let blocks = response.results
Utilities.sleep(50)
// guard clause
if (blocks.length == 0) {
return
}
blocks = blocks.concat(blocks.map((block) => getSubBlocks(block.id)).flat())
// get rid of undefined
blocks = blocks.filter(block => block != undefined)
return blocks
}
I am trying to make a identical function from node.js, but I have trouble in unwrapping all the blocks. The below is the node-js version of the recursive function
import fetch from "node-fetch";
// recursive function to get all nested blocks in a flattened array format
async function getSubBlocks(blockId) {
const url = `https://api.notion.com/v1/blocks/${blockId}/children?page_size=100`;
let options = {
async: true,
crossDomain: true,
method: "get",
headers: {
Authorization: `Bearer ${NOTION_API_KEY}`,
"Notion-Version": "2022-02-22",
"Content-Type": "application/json",
},
};
const response = await fetch(url, options);
const r = await response.json();
let blocks = r.results;
// guard clause ends the function if the array is empty
if (blocks.length == 0) {
return;
}
// for each block objects, check for children blocks in a recursive manner
let newBlocks = await blocks
.map(async (block) => await getSubBlocks(block.id))
.flat();
blocks = blocks.concat(newBlocks);
// get rid of undefined
blocks = blocks.filter((block) => block != undefined);
return await blocks;
}
getSubBlocks(testBlock)
.then((r) => console.log(r))
.catch((error) => console.log(error));
I understand that the above function is an async function, so it always returns a promise. That is why I am trying to unwrap the promise with a then clause, but I only get the first blocks unwrapped, and the other blocks from the recursive calls are still presented as promises. An example output is as below:
[
{
object: 'block',
id: 'XXXXXXXXXXXX',
created_time: '2022-05-28T05:15:00.000Z',
last_edited_time: '2022-05-28T05:15:00.000Z',
created_by: { object: 'user', id: 'XXXXXX' },
last_edited_by: { object: 'user', id: 'XXXXXX' },
has_children: false,
archived: false,
type: 'paragraph',
paragraph: { rich_text: [Array], color: 'default' }
},
{
object: 'block',
id: 'XXXXXXXXXXXX',
created_time: '2022-05-28T05:15:00.000Z',
last_edited_time: '2022-05-28T05:15:00.000Z',
created_by: { object: 'user', id: 'XXXXXXXXXXXX' },
last_edited_by: { object: 'user', id: 'XXXXXXXXXXXX' },
has_children: false,
archived: false,
type: 'paragraph',
paragraph: { rich_text: [], color: 'default' }
},
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
]
Is there any way to solve this issue?
In a more broader sense, is there any best practice to retrieve all values when using recursion and fetch?
CodePudding user response:
Your getSubBlocks
function does not return a Promise
.
Also, you may want to change your approach from map
to a normal for...of
loop to simplify your code and remove some unnecessary await
.
Try with this approach:
import fetch from 'node-fetch';
// recursive function to get all nested blocks in a flattened array format
async function getSubBlocks(blockId) {
const url = `https://api.notion.com/v1/blocks/${blockId}/children?page_size=100`;
let options = {
async: true,
crossDomain: true,
method: 'get',
headers: {
Authorization: `Bearer ${NOTION_API_KEY}`,
'Notion-Version': '2022-02-22',
'Content-Type': 'application/json',
},
};
const response = await fetch(url, options);
const r = await response.json();
let blocks = r.results;
// guard clause ends the function if the array is empty
if (blocks && blocks.length == 0) {
return undefined;
}
// for each block objects, check for children blocks in a recursive manner
for (const block of blocks) {
const subBlocks = await getSubBlocks(block.id)
if (subBlocks) blocks = [...blocks, ...subBlocks]
}
return blocks;
}
const res = getSubBlocks(testBlock)