Yes, your hunch is correct! @mburridge
In some circumstances, Frontity cannot know just based on the slug if the entity that you are requesting is a post
or a page
. If you go to https://my-site/about-us, it’s both a valid page URL and a valid post URL.
For this reason we have to make a request to both endpoints in order to know which one it is.
You check out the relevant source code where we match the link with a pattern and then invoke the postType
handler for that link (which could be a post, page or attachement).
The postType
handler is created via a “generator function” here
That “generator function” will iterate over post, page and media endpoints fetching the data from each.
@David :
There’s one thing that I’m not certain about. In the postType
handler we are fetching the data serially from each endpoint (post
, then page
and then media
). Is the order of the endpoints
in the postType
handler intentional or not? In other words, do we intentionally check post
before page
and page
before media
?
If it is not intentional, we could optimize that part and fetch the data in parallel. I’ve just done a little modification which fetches in parallel and it seems to work just fine with the mars-theme:
libraries/handlers/postType.ts
// Turn an array of promises into a generator.
// This allows us to iterate over them with `for await...of`
async function* getData(promises: Promise<any>[]) {
const map = new Map(
promises.map((p, i) => [i, p.then((res) => [i, res])])
);
while (map.size) {
const [key, result] = await Promise.race(map.values());
yield result;
map.delete(key);
}
}
const promises = finalEndpoints.map((endpoint) =>
libraries.source.api.get({
endpoint,
params: { slug, _embed: true, ...state.source.params },
})
);
const responses = getData(promises);
// Here we iterate asynchronously. This means that we
// pull the new response from `responses` as soon as it is received.
for await (const response of responses) {
const populated = await libraries.source.populate({
response,
state,
force,
});
// exit loop if this endpoint returns an entity!
if (populated.length > 0) {
// We have to check if the link property in the data that we
// populated is the same as the current route.
if (populated[0].link === route) {
isHandled = true;
isMismatched = false;
matchedEndpoint = populated[0].type;
break;
} else {
isMismatched = true;
}
}
}