Skip to content

Instantly share code, notes, and snippets.

@emmaly
Created March 8, 2023 06:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emmaly/f5bc190d7b98653b508899cbd0c2b0fc to your computer and use it in GitHub Desktop.
Save emmaly/f5bc190d7b98653b508899cbd0c2b0fc to your computer and use it in GitHub Desktop.
JSON:API relationship resolver
function resolveRelationships(relationships, included, parentIds) {
if (typeof relationships !== "object" || !Object.keys(relationships).length) return [];
if (typeof included !== "object" || !Array.isArray(included)) return [];
if (typeof parentIds === "string") parentIds = [parentIds];
if (typeof parentIds !== "object" || !Array.isArray(parentIds)) parentIds = [];
/**
* @param {string} type
* @returns {string}
*/
const normalizeType = (type) => type.replaceAll("_","-"); // workaround due to IT Glue not following JSON:API spec
/**
* @param {Object<string,Object>} relationships
* @returns {Object<string,Object[]>}
*/
const normalizeRelationships = (relationships) => {
if (typeof relationships !== "object") return {};
const data = {};
const fileItem = (item) => {
if (typeof item !== "object") return;
if (typeof item.type !== "string") return;
if (typeof item.id !== "string") return;
if (parentIds.includes(item.id)) return; // skip circular references
item.type = normalizeType(item.type);
if (!data[item.type]) data[item.type] = [];
data[item.type].push(item);
};
if (Array.isArray(relationships)) {
relationships.forEach(fileItem);
} else {
Object.values(relationships).forEach((value) => {
if (typeof value !== "object") return;
if (typeof value.data === "object") {
if (Array.isArray(value.data)) {
value.data.forEach(fileItem);
} else {
fileItem(value.data);
}
} else {
fileItem(value);
}
});
}
return data;
};
/**
* @param {string} type
* @param {string} id
* @param {Object[]} included
* @param {string[]} parentIds
* @returns {Object[]}
*/
const resolveRelationship = (type, id, included, parentIds) => {
if (typeof id !== "string" || typeof type !== "string") return [];
if (typeof included !== "object" || !Array.isArray(included)) return [];
return included
// .filter((item) => !parentIds.includes(item.id))
.map((item) => {item.type = normalizeType(item.type); return item})
.filter((item) => item.id === id && item.type === type)
.map((item) => {
if (!item.relationships) return item;
return {
...item,
relationships: resolveRelationships(item.relationships, included, [...parentIds, item.id])
};
});
};
return Object.fromEntries(
Object.entries(normalizeRelationships(relationships))
.map(([key, items]) => {
if (!Array.isArray(items)) return {"qqq":"???","items":items};
return [
key,
items
.map((item) => resolveRelationship(item.type, item.id, included, parentIds))
.reduce((a, v) => [...a, ...v], [])
];
})
.filter(([{}, items]) => Array.isArray(items) && items.length)
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment