{"id":21692784,"url":"https://github.com/swaggerexpert/json-api-merge","last_synced_at":"2025-10-09T11:03:40.118Z","repository":{"id":37917006,"uuid":"232339896","full_name":"swaggerexpert/json-api-merge","owner":"swaggerexpert","description":"JSON:API specific algorithm for merging included resources into original data.","archived":false,"fork":false,"pushed_at":"2025-06-13T14:50:15.000Z","size":6114,"stargazers_count":25,"open_issues_count":5,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-13T15:47:58.122Z","etag":null,"topics":["api","duplication","included","json","jsonapi","merge","redundant"],"latest_commit_sha":null,"homepage":"https://jsonapi.org/format/#document-top-level","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/swaggerexpert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":"GOVERNANCE.md","roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["char0n"],"tidelift":"npm/@swaggerexpert%2Fjson-api-merge","patreon":"char0n","ko_fi":"char0n","liberapay":"char0n","issuehunt":"char0n"}},"created_at":"2020-01-07T14:17:50.000Z","updated_at":"2025-06-13T14:49:03.000Z","dependencies_parsed_at":"2024-02-05T15:58:02.585Z","dependency_job_id":"e30eb42d-1451-4dda-ba2a-c3f3fa65f368","html_url":"https://github.com/swaggerexpert/json-api-merge","commit_stats":{"total_commits":1124,"total_committers":4,"mean_commits":281.0,"dds":0.08096085409252674,"last_synced_commit":"12450e69254aa55088f33c70845fabbd22adbd9b"},"previous_names":["swaggerexpert/json-api-merge"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/swaggerexpert/json-api-merge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fjson-api-merge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fjson-api-merge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fjson-api-merge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fjson-api-merge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swaggerexpert","download_url":"https://codeload.github.com/swaggerexpert/json-api-merge/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fjson-api-merge/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260896105,"owners_count":23078951,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","duplication","included","json","jsonapi","merge","redundant"],"created_at":"2024-11-25T18:17:22.237Z","updated_at":"2025-10-09T11:03:40.040Z","avatar_url":"https://github.com/swaggerexpert.png","language":"JavaScript","funding_links":["https://github.com/sponsors/char0n","https://tidelift.com/funding/github/npm/@swaggerexpert%2Fjson-api-merge","https://patreon.com/char0n","https://ko-fi.com/char0n","https://liberapay.com/char0n","https://issuehunt.io/r/char0n","https://tidelift.com/badges/package/npm/@swaggerexpert%2Fjson-api-merge","https://tidelift.com/subscription/pkg/npm-.swaggerexpert-json-api-merge?utm_source=npm-swaggerexpert-json-api-merge\u0026utm_medium=referral\u0026utm_campaign=readme"],"categories":[],"sub_categories":[],"readme":"# JSON API Merge\n\n[![npmversion](https://badge.fury.io/js/@swaggerexpert%2Fjson-api-merge.svg)](https://www.npmjs.com/package/@swaggerexpert/json-api-merge)\n[![npm](https://img.shields.io/npm/dm/@swaggerexpert/json-api-merge)](https://www.npmjs.com/package/@swaggerexpert/json-api-merge)\n[![Node CI](https://github.com/swaggerexpert/json-api-merge/workflows/Node.js%20CI/badge.svg)](https://github.com/swaggerexpert/json-api-merge/actions?query=workflow%3A%22Node.js+CI%22)\n[![Dependabot enabled](https://img.shields.io/badge/Dependabot-enabled-blue.svg)](https://dependabot.com/)\n[![try on RunKit](https://img.shields.io/badge/try%20on-RunKit-brightgreen.svg?style=flat)](https://npm.runkit.com/@swaggerexpert/json-api-merge)\n[![Tidelift](https://tidelift.com/badges/package/npm/@swaggerexpert%2Fjson-api-merge)](https://tidelift.com/subscription/pkg/npm-.swaggerexpert-json-api-merge?utm_source=npm-swaggerexpert-json-api-merge\u0026utm_medium=referral\u0026utm_campaign=readme)\n\n`@swaggerexpert/json-api-merge` is a JSON:API specific redundant duplication algorithm for merging included resources into original data.\n\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"right\" valign=\"middle\"\u003e\n        \u003cimg src=\"https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png\" alt=\"Tidelift\" width=\"60\" /\u003e\n      \u003c/td\u003e\n      \u003ctd valign=\"middle\"\u003e\n        \u003ca href=\"https://tidelift.com/subscription/pkg/npm-.swaggerexpert-json-api-merge?utm_source=npm-swaggerexpert-json-api-merge\u0026utm_medium=referral\u0026utm_campaign=readme\"\u003e\n            Get professionally supported @swaggerexpert/json-api-merge with Tidelift Subscription.\n        \u003c/a\u003e\n      \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Getting Started\n\n### Installation\n\n```sh\nnpm i @swaggerexpert/json-api-merge\n```\nor\n```sh\nyarn add @swaggerexpert/json-api-merge\n```\n\n### Usage\n\n```js\nconst jsonApiData = {\n  data: {\n    id: 1,\n    type: 'resource',\n    attributes: {\n      name: 'Resource name',\n    },\n    relationships: {\n      related: {\n        data: {\n          id: 2,\n          type: 'related_resource',\n        },\n      },\n    },\n  },\n  included: [\n    {\n      id: 2,\n      type: 'related_resource',\n      attributes: {\n        name: 'Related resource name',\n      },\n    },\n  ],\n};\n```\n\n#### ES modules\n\n```javascript\nimport jsonApiMerge from '@swaggerexpert/json-api-merge'\n\njsonApiMerge(jsonApiData.included, jsonApiData.data)\n```\n\n#### CommonJS\n\n```javascript\nconst jsonApiMerge = require('@swaggerexpert/json-api-merge');\n\njsonApiMerge(jsonApiData.included, jsonApiData.data);\n```\n\nResult would be following data structure.\n\n```js\n{\n  id: 1,\n  type: 'resource',\n  attributes: {\n   name: 'Resource name',\n  },\n  relationships: {\n    related: {\n      data: {\n       id: 2,\n       type: 'related_resource',\n       attributes: {\n         name: 'Related resource name',\n       },\n      },\n    },\n  },\n}\n```\n\nThe library can also process data in **list** format and can transform this:\n\n```js\n{\n  data: [\n    {\n      id: 1,\n      type: 'resource',\n      attributes: {\n        name: 'Resource name',\n      },\n      relationships: {\n        related: {\n          data: {\n            id: 2,\n            type: 'related_resource',\n          },\n        },\n      },\n    }\n  ],\n  included: [\n    {\n      id: 2,\n      type: 'related_resource',\n      attributes: {\n        name: 'Related resource name',\n      },\n    },\n  ],\n}\n```\n\ninto this:\n\n```js\n[\n  {\n    id: 1,\n    type: 'resource',\n    attributes: {\n      name: 'Resource name',\n    },\n    relationships: {\n      related: {\n        data: {\n          id: 2,\n          type: 'related_resource',\n          attributes: {\n            name: 'Related resource name',\n          },\n        },\n      },\n    },\n  }\n]\n```\n\n### Compound document\n\nTo reduce the number of HTTP requests, servers MAY allow responses that include related resources\nalong with the requested primary resources. Such responses are called [“compound documents”](https://jsonapi.org/format/1.1/#document-compound-documents).\n\n```js\nconst jsonApiData = {\n  data: [\n    {\n      type: 'articles',\n      id: '1',\n      attributes: {\n        title: 'JSON:API paints my bikeshed!',\n      },\n      links: {\n        self: 'http://example.com/articles/1',\n      },\n      relationships: {\n        author: {\n          links: {\n            self: 'http://example.com/articles/1/relationships/author',\n            related: 'http://example.com/articles/1/author',\n          },\n          data: { type: 'people', id: '9' },\n        },\n        comments: {\n          links: {\n            self: 'http://example.com/articles/1/relationships/comments',\n            related: 'http://example.com/articles/1/comments',\n          },\n          data: [\n            { type: 'comments', id: '5' },\n            { type: 'comments', id: '12' },\n          ],\n        },\n      },\n    },\n  ],\n  included: [\n    {\n      type: 'people',\n      id: '9',\n      attributes: {\n        firstName: 'Dan',\n        lastName: 'Gebhardt',\n        twitter: 'dgeb',\n      },\n      links: {\n        self: 'http://example.com/people/9',\n      },\n    },\n    {\n      type: 'comments',\n      id: '5',\n      attributes: {\n        body: 'First!',\n      },\n      relationships: {\n        author: {\n          data: { type: 'people', id: '2' },\n        },\n      },\n      links: {\n        self: 'http://example.com/comments/5',\n      },\n    },\n    {\n      type: 'comments',\n      id: '12',\n      attributes: {\n        body: 'I like XML better',\n      },\n      relationships: {\n        author: {\n          data: { type: 'people', id: '9' },\n        },\n      },\n      links: {\n        self: 'http://example.com/comments/12',\n      },\n    },\n  ],\n};\n```\n\nCompound documents can achieve full linkage with the following trick:\n\n```js\nconst included = jsonApiMerge(jsonApiData.included, jsonApiData.included);\njsonApiMerge(included, jsonApiData.data);\n```\n\nThis operation will generate following compound document with full linkage:\n\n````js\n[\n  {\n    type: 'articles',\n    id: '1',\n    attributes: {\n      title: 'JSON:API paints my bikeshed!',\n    },\n    links: {\n      self: 'http://example.com/articles/1',\n    },\n    relationships: {\n      author: {\n        links: {\n          self: 'http://example.com/articles/1/relationships/author',\n          related: 'http://example.com/articles/1/author',\n        },\n        data: {\n          type: 'people',\n          id: '9',\n          attributes: {\n            firstName: 'Dan',\n            lastName: 'Gebhardt',\n            twitter: 'dgeb',\n          },\n          links: {\n            self: 'http://example.com/people/9',\n          },\n        },\n      },\n      comments: {\n        links: {\n          self: 'http://example.com/articles/1/relationships/comments',\n          related: 'http://example.com/articles/1/comments',\n        },\n        data: [\n          {\n            type: 'comments',\n            id: '5',\n            attributes: {\n              body: 'First!',\n            },\n            relationships: {\n              author: {\n                data: {\n                  type: 'people',\n                  id: '2',\n                },\n              },\n            },\n            links: {\n              self: 'http://example.com/comments/5',\n            },\n          },\n          {\n            type: 'comments',\n            id: '12',\n            attributes: {\n              body: 'I like XML better',\n            },\n            relationships: {\n              author: {\n                data: {\n                  type: 'people',\n                  id: '9',\n                  attributes: {\n                    firstName: 'Dan',\n                    lastName: 'Gebhardt',\n                    twitter: 'dgeb',\n                  },\n                  links: {\n                    self: 'http://example.com/people/9',\n                  },\n                },\n              },\n            },\n            links: {\n              self: 'http://example.com/comments/12',\n            },\n          },\n        ],\n      },\n    },\n  },\n];\n````\n\n## Motivation\n\nI was looking for a simple way how to merge the `included` into `data` without compromising data\nstructures. All other libraries that I tested were opinionated about how the resulting merge should look like.\nThis library has no opinion and simply merged the `included` into `data`. It does nothing else.\n\n## Contributing\n\nIf you want to contribute to this project, please consult the [CONTRIBUTING.md](https://github.com/swaggerexpert/ramda-adjunct/blob/master/CONTRIBUTING.md) guidelines.\n\n**Obtaining project copy**\n\n```sh\n $ git clone https://github.com/swaggerexpert/json-api-merge\n $ npm i\n```\n\n**Running tests**\n```sh\n $ npm run test\n```\n\n**Running tests in browser**\n```sh\n $ npm run test:web\n```\n\n\n**Running linter**\n\nWe're using [eslint](https://eslint.org/) and [airbnb codestyle](https://github.com/airbnb/javascript) rules with [prettier](https://prettier.io/) integrated as an eslint plugin.\n\n```sh\n $ npm run lint\n```\n\n## Typescript support\n\nAlthough @swaggerexpert/json-api-merge is written in ES2019, we also support **Typescript**.\nWhen @swaggerexpert/json-api-merge gets imported into a Typescript project, typings are automatically imported and used.\n\n## Author\n\nchar0n (Vladimír Gorej) \\\ncontact@swaggerexpert.com \\\nhttps://swaggerexport.com/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswaggerexpert%2Fjson-api-merge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswaggerexpert%2Fjson-api-merge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswaggerexpert%2Fjson-api-merge/lists"}