{"id":17066810,"url":"https://github.com/tobyzerner/json-api-models","last_synced_at":"2025-04-12T18:20:51.697Z","repository":{"id":38389686,"uuid":"222580723","full_name":"tobyzerner/json-api-models","owner":"tobyzerner","description":"A lightweight layer for working with JSON:API data.","archived":false,"fork":false,"pushed_at":"2025-01-22T04:44:13.000Z","size":743,"stargazers_count":28,"open_issues_count":4,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-26T12:37:50.190Z","etag":null,"topics":["json-api"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tobyzerner.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"tobyzerner"}},"created_at":"2019-11-19T01:27:05.000Z","updated_at":"2025-01-24T01:17:22.000Z","dependencies_parsed_at":"2024-12-05T03:33:52.897Z","dependency_job_id":null,"html_url":"https://github.com/tobyzerner/json-api-models","commit_stats":{"total_commits":55,"total_committers":4,"mean_commits":13.75,"dds":"0.10909090909090913","last_synced_commit":"083c0fed26603467216c12b4fbe5bf0493b358bc"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobyzerner%2Fjson-api-models","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobyzerner%2Fjson-api-models/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobyzerner%2Fjson-api-models/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobyzerner%2Fjson-api-models/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tobyzerner","download_url":"https://codeload.github.com/tobyzerner/json-api-models/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248610686,"owners_count":21132984,"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":["json-api"],"created_at":"2024-10-14T11:08:25.248Z","updated_at":"2025-04-12T18:20:51.668Z","avatar_url":"https://github.com/tobyzerner.png","language":"TypeScript","funding_links":["https://github.com/sponsors/tobyzerner"],"categories":[],"sub_categories":[],"readme":"# json-api-models\n\n\u003e A lightweight layer for working with [JSON:API](http://jsonapi.org) data.\n\n## Installation\n\n```\nnpm install json-api-models --save\n```\n\n## Usage\n\n```ts\nimport { Store } from 'json-api-models';\n\nconst models = new Store();\n\n// Sync a JSON:API response document to the store\nmodels.sync({\n    data: {\n        type: 'users',\n        id: '1',\n        attributes: { name: 'Toby' },\n        relationships: {\n            pet: { data: { type: 'dogs', id: '1' } },\n        },\n    },\n    included: [\n        {\n            type: 'dogs',\n            id: '1',\n            attributes: { name: 'Rosie' },\n        },\n    ],\n});\n\n// Resource data is transformed into easy-to-consume models\nconst user = models.find('users', '1');\nuser.name; // Toby\nuser.pet; // { type: 'dogs', id: '1', name: 'Rosie' }\n```\n\n### Syncing JSON:API Data\n\nUse the `sync` method to load your JSON:API response document into the store. Both the primary `data` and any `included`\nresources will be synced. The return value will be a model, or an array of models, corresponding to the primary data.\n\n```ts\nconst model = models.sync(document);\n```\n\nIf any of the synced resources already exist within the store, the new data will be **merged** into the old model. The\nmodel instance will not change so references to it throughout your application will remain intact.\n\nYou can also sync an individual resource using the `syncResource` method:\n\n```ts\nconst model = models.syncResource({\n    type: 'users',\n    id: '1',\n    attributes: { name: 'Toby' },\n});\n```\n\n### Retrieving Models\n\nSpecific models can be retrieved from the store using the `find` method. Pass it a type and an ID, a resource identifier\nobject, or an array of resource identifier objects:\n\n```ts\nconst user = models.find('users', '1');\nconst user = models.find({ type: 'users', id: '1' });\nconst users = models.find([\n    { type: 'users', id: '1' },\n    { type: 'users', id: '2' },\n]);\n```\n\nRetrieve all of the models of a given type using the `findAll` method:\n\n```ts\nconst users = models.findAll('users');\n```\n\n### Working with Models\n\nModels are a _superset_ of JSON:API resource objects, meaning they contain all of the members you would\nexpect (`type`, `id`, `attributes`, `relationships`, `meta`, `links`) plus some additional functionality.\n\nGetters are automatically defined for all fields, allowing you to easily access their contents. Relationship fields are\nautomatically resolved to their related models (if present within the store):\n\n```ts\nmodel.name; // =\u003e model.attributes.name\nmodel.pet; // =\u003e models.find(model.relationships.pet.data)\n```\n\nTo easily retrieve a resource identifier object for the model, the `identifier` method is available. This is useful when\nconstructing relationships in JSON:API request documents.\n\n```ts\nmodel.identifier(); // { type: 'users', id: '1' }\n```\n\n### Forgetting Models\n\nRemove a model from the store using the `forget` method, which accepts a resource identifier object. This means you can\npass a model directly into it:\n\n```ts\nmodels.forget(user);\n```\n\n### Custom Models\n\nYou can define custom model classes to add your own functionality. Custom models must extend the `Model` base class.\nThis is useful if you wish to add any custom getters or methods to models for a specific resource type:\n\n```ts\nimport { Model } from 'json-api-models';\n\nclass User extends Model {\n    get firstName() {\n        return this.name.split(' ')[0];\n    }\n}\n```\n\nRegister your custom models with the store during construction:\n\n```ts\nconst models = new Store({\n    users: User,\n});\n```\n\n### TypeScript\n\nFor TypeScript autocompletion of model attributes and relationships, provide the raw JSON:API resource schema when defining your models.\n\n```ts\ntype UsersSchema = {\n    type: 'users';\n    id: string;\n    attributes: {\n        name: string;\n    };\n    relationships: {\n        dog: { data?: { type: 'dogs'; id: string } | null };\n    };\n};\n\nclass User extends Model\u003cUsersSchema\u003e {}\n```\n\nTo type related resources, you can provide a collection of all models as the second generic.\n\n```ts\ntype DogsSchema = {\n    // ...\n};\n\ntype Schemas = {\n    users: User;\n    dogs: Dog;\n};\n\nclass User extends Model\u003cUsersSchema, Schemas\u003e {}\nclass Dog extends Model\u003cDogsSchema, Schemas\u003e {}\n```\n\n### API Consumption Tips\n\nThis library is completely unopinionated about how you interact with your JSON:API server. It merely gives you an easy\nway to work with the resulting JSON:API data. An example integration with `fetch` is demonstrated below:\n\n```ts\nconst models = new Store();\n\nfunction api(url, options = {}) {\n    options.headers = options.headers || {};\n    options.headers['Accept'] = 'application/vnd.api+json';\n\n    if (options.body) {\n        options.body = JSON.stringify(options.body);\n        options.headers['Content-Type'] = 'application/vnd.api+json';\n    }\n\n    return fetch('http://example.org/api/' + url, options).then(\n        async (response) =\u003e {\n            if (response.status === 204) {\n                return { response };\n            } else {\n                const document = await response.json();\n                const data = models.sync(document);\n                return { response, document, data };\n            }\n        },\n    );\n}\n\napi('users/1').then(({ data }) =\u003e {\n    console.log(data.name);\n});\n```\n\nWhen constructing API requests, remember that JSON:API resource objects contain `links` that can be used instead of\nrebuilding the URL. Also, models contain an `identifier` method that can be used to spread the `type` and `id` members\ninto the document `data` (required by the specification). Here is an example of a request to update a resource:\n\n```ts\nconst user = models.find('users', '1');\n\napi(user.links.self, {\n    method: 'PATCH',\n    body: {\n        data: {\n            ...user.identifier(),\n            attributes: { name: 'Changed' },\n        },\n    },\n});\n```\n\n## Contributing\n\nPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobyzerner%2Fjson-api-models","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftobyzerner%2Fjson-api-models","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobyzerner%2Fjson-api-models/lists"}