{"id":18864947,"url":"https://github.com/digitalsadhu/loopback-component-jsonapi","last_synced_at":"2025-10-20T09:35:36.170Z","repository":{"id":44936663,"uuid":"42947993","full_name":"digitalsadhu/loopback-component-jsonapi","owner":"digitalsadhu","description":"JSONAPI support for loopback. ","archived":false,"fork":false,"pushed_at":"2023-08-08T18:24:08.000Z","size":603,"stargazers_count":102,"open_issues_count":56,"forks_count":32,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-07-09T09:22:17.583Z","etag":null,"topics":["custom-serialization","deserialization","json-api","jsonapi","loopback","loopback-component","serialization","serialization-process"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/digitalsadhu.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2015-09-22T17:00:25.000Z","updated_at":"2025-05-06T08:19:17.000Z","dependencies_parsed_at":"2024-06-19T01:26:11.455Z","dependency_job_id":"53ab9e6f-3ccc-4df9-be3e-f95e7019d592","html_url":"https://github.com/digitalsadhu/loopback-component-jsonapi","commit_stats":null,"previous_names":[],"tags_count":58,"template":false,"template_full_name":null,"purl":"pkg:github/digitalsadhu/loopback-component-jsonapi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalsadhu%2Floopback-component-jsonapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalsadhu%2Floopback-component-jsonapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalsadhu%2Floopback-component-jsonapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalsadhu%2Floopback-component-jsonapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/digitalsadhu","download_url":"https://codeload.github.com/digitalsadhu/loopback-component-jsonapi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalsadhu%2Floopback-component-jsonapi/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267228084,"owners_count":24056366,"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","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["custom-serialization","deserialization","json-api","jsonapi","loopback","loopback-component","serialization","serialization-process"],"created_at":"2024-11-08T04:44:34.199Z","updated_at":"2025-10-20T09:35:36.075Z","avatar_url":"https://github.com/digitalsadhu.png","language":"JavaScript","readme":"# loopback-component-jsonapi\n\n[![Greenkeeper badge](https://badges.greenkeeper.io/digitalsadhu/loopback-component-jsonapi.svg)](https://greenkeeper.io/)\n\n[![Join the chat at https://gitter.im/digitalsadhu/loopback-component-jsonapi](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/digitalsadhu/loopback-component-jsonapi?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![Build Status](https://travis-ci.org/digitalsadhu/loopback-component-jsonapi.svg)](https://travis-ci.org/digitalsadhu/loopback-component-jsonapi)\n[![npm version](https://badge.fury.io/js/loopback-component-jsonapi.svg)](http://badge.fury.io/js/loopback-component-jsonapi)\n[![Dependency Status](https://david-dm.org/digitalsadhu/loopback-component-jsonapi.svg)](https://david-dm.org/digitalsadhu/loopback-component-jsonapi)\n[![devDependency Status](https://david-dm.org/digitalsadhu/loopback-component-jsonapi/dev-status.svg)](https://david-dm.org/digitalsadhu/loopback-component-jsonapi#info=devDependencies)\n[![Coverage Status](https://coveralls.io/repos/github/digitalsadhu/loopback-component-jsonapi/badge.svg?branch=master)](https://coveralls.io/github/digitalsadhu/loopback-component-jsonapi?branch=master)\n\n[jsonapi.org](http://jsonapi.org/) support for loopback.\n\n## Status\n\nThis project is now pretty stable and is used in production in a number of our projects.\nThere are known issues (see below and the issue tracker) these can mostly be worked around or\nare pretty minor. Open an issue on the issue tracker if you need clarification on anything or\nneed help.\n\n### Known issues\n\nThis module doesn't do complex compound documents very well yet. This means that if you try to do complex\nincludes in a single request you will likely run into trouble.\n\nWe wrote another module called [loopback-jsonapi-model-serializer](https://www.npmjs.com/package/loopback-jsonapi-model-serializer)\nthat does JSONAPI serialization very well (but nothing else) for loopback which you can use to get\naround such issues for now. The long term goal is to swap out the serialization layer in\n`loopback-component-jsonapi` with `loopback-jsonapi-model-serializer`\n\n## Tested against:\n\n- Node 4, 6 and 8\n- JSON API v1.0\n- loopback ^3.8.0\n\n## Sample Project\nWe have created a sample project using [EmberJS](http://emberjs.com), [Loopback](http://loopback.io) and this compoment. It's called [emberloop](https://github.com/tsteuwer/emberloop).\n\n## Helping out\nWe are VERY interested in help. Get in touch via the [issue tracker](https://github.com/digitalsadhu/loopback-component-jsonapi/issues)\nPlease read the following about contributing:\n\n### Semantic Release\n\nThis project uses [Semantic Release](https://github.com/semantic-release/semantic-release) to manage the release process.\nThis means that:\nA. There is no semver project version in `package.json`. This is managed in CI.\nB. Commit messages need to follow conventions. See [here](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit) for commit message guidelines.\nThe important things to remember are:\nA. If you are fixing a bug prefix your commit message with `fix(\u003cthing being fixed goes here\u003e):`\nB. If you are adding a non breaking feature, prefix your commit with `feat(\u003cname of feature goes here\u003e):`\nC. If you are making a breaking change of any kind, prefix additional information on the 3rd line of the commit message with: `BREAKING CHANGE:`\nSee examples of this on the [Semantic Release](https://github.com/semantic-release/semantic-release) github pages.\nAnd don't hesitate to reach out on our [issue tracker](https://github.com/digitalsadhu/loopback-component-jsonapi/issues)\nif you want further clarification.\n\n### Standard js and \"prettier standard\"\n\nThis project is follows the [Standard js](https://standardjs.com/) styleguide. Linting happens on CI and any time you run tests via `npm test`\nYou can run the linting on its own with `npm run lint`\n\nAdditionally, code formatting is done whenever you run git commit. This is made possibly by [lint-staged](https://github.com/okonet/lint-staged) and [husky](https://github.com/typicode/husky) with actual formatting done by\n[prettier](https://github.com/prettier/prettier)\n\n### Pull requests and code review\n\nAll code is reviewed by one or more of the project maintainers before merging. Before becoming a maintainer, contributers\nneed to fork the master branch of this repo, make their changes and submit a pull request.\n\nOnce a contributor becomes a maintainer, it is preferred that they create new branches on the loopback-component-jsonapi\nrepo and submit those as pull requests\n\n### Tests\n\nWe take testing seriously. The project contains over 200 tests at time of writing this. In most cases we wont merge\nanything without tests. (Within reason of course)\n\n### Project maintainers\n\nWe follow the principle of \"Open open source\" which means if you contribute even a single PR to the project, we make you\na project maintainer.\n\n## Debugging\nYou can enable debug logging by setting an environment variable:\n`DEBUG=loopback-component-jsonapi`\n\n#### example:\n```\nDEBUG=loopback-component-jsonapi node .\n```\n\n# API Documentation\n\n## Getting started\n\nIn your loopback project:\n\n1. `npm install --save loopback-component-jsonapi`\n2. Create a `component-config.json` file in your server folder (if you don't already have one)\n3. Add the following config to `component-config.json`\n\n```json\n{\n  \"loopback-component-jsonapi\": {}\n}\n```\n\n## Advanced usage:\nWe are aiming to make the component as configurable as possible. You can configure how the component behaves with the options shown and listed below. If there is something else you would like to see be configurable, please submit an issue on the repository. For remote methods, `root` must be set to `true`.\n\nExample:\n(all configuration options listed)\n```json\n{\n  \"loopback-component-jsonapi\": {\n    \"restApiRoot\": \"/api\",\n    \"host\": \"https://www.mydomain.com\",\n    \"enable\": true,\n    \"handleErrors\": true,\n    \"errorStackInResponse\": false,\n    \"handleCustomRemoteMethods\": false,\n    \"exclude\": [\n      {\"model\": \"comment\"},\n      {\"methods\": \"find\"},\n      {\"model\": \"post\", \"methods\": \"find\"},\n      {\"model\": \"person\", \"methods\": [\"find\", \"create\"]}\n    ],\n    \"hideIrrelevantMethods\": true,\n    \"attributes\": {\n      \"posts\": [\"title\"]\n    },\n    \"include\": [\n      {\"methods\": \"customMethod\"},\n      {\"model\": \"post\", \"methods\": \"customMethod\"},\n      {\"model\": \"person\", \"methods\": [\"customMethod1\", \"customMethod2\"]}\n    ]\n  }\n}\n```\n\n### restApiRoot\nUrl prefix to be used in conjunction with host and resource paths. eg. http://127.0.0.1:3214/api/people\n\n#### example\n```js\n{\n  ...\n  \"restApiRoot\": \"/api\",\n  ...\n}\n```\n\n- Type: `string`\n- Default: `/api`\n\n### host\nThe url of the application, to be used when constructing links to relationships.  Useful where the service is proxied and the application believes\nit is running on a different url to that seen by the consuming service.\n\n#### example\n```js\n{\n  ...\n  \"host\": \"https://www.mydomain.com\",\n  ...\n}\n```\n\n- Type: `string`\n- Default: `null`\n\n### enable\nWhether the component should be enabled or disabled. Defaults to `true`, flip it to `false` if you need to turn the component off without removing the configuration for some reason.\n\n#### example\n```js\n{\n  ...\n  \"enable\": true,\n  ...\n}\n```\n\n- Type: `boolean`\n- Default: `true`\n\n### handleErrors\nWhen true, the component will unregister all other error handling and\nregister a custom error handler which always returns errors in JSON API compliant\nformat. Validation errors include the correct properties in order to work\nout of the box with EmberJS.\n\n#### example\n```js\n{\n  ...\n  \"handleErrors\": true,\n  ...\n}\n```\n\n- Type: `boolean`\n- Default: `true`\n\n### errorStackInResponse\nAlong handleErrors, When true, this option will send the error stack if available within the error\nresponse. It will be stored under the `source.stack` key.\n\n**Please be careful, this option should never be enabled in a production environment. Doing so can expose sensitive data.**\n\n#### example\n```js\n{\n  ...\n  \"errorStackInResponse\": NODE_ENV === 'development',\n  ...\n}\n```\n\n- Type: `boolean`\n- Default: `false`\n\n### handleCustomRemoteMethods\nAllow all (custom) remote methods to be serialized by default.\n\nThis option can be overridden in any of the following ways:\n1. Setting a jsonapi property to true or false in a remote method definition.\n2. Globally adding the remote method to the component's exclude array.\n3. Globally adding the remote method to the component's include array.\n\n#### example\n```js\n{\n  ...\n  \"handleCustomRemoteMethods\": true,\n  ...\n}\n```\n\n- Type: `boolean`\n- Default: `false`\n\n### exclude\nAllows blacklisting of models and methods.\nDefine an array of blacklist objects. Blacklist objects can contain \"model\" key\n\"methods\" key or both. If just \"model\" is defined then all methods for the\nspecified model will not be serialized of deserialized using JSON API. If just the \"methods\" key is defined then\nall methods specified on all models will not be serialized or deserialized using JSON API. If a combination of\n\"model\" and \"methods\" keys are used then the specific combination of model and methods\nspecified will not be serialized or deserialized using JSON API.\n\n#### example\n```js\n{\n  ...\n  \"exclude\": [\n    {\"model\": \"comment\"},\n    {\"methods\": \"find\"},\n    {\"model\": \"post\", \"methods\": \"find\"},\n    {\"model\": \"person\", \"methods\": [\"find\", \"create\"]}\n  ],\n  ...\n}\n```\n\n- Type: `array`\n- Default: `null`\n\n#### Note\nThe default behavior is to modify (serialize to JSON API) the output of the following CRUD methods on all models:\n- `find`\n- `create`\n- `updateAttributes`\n- `deleteById`\n- `findById`\n\nIn addition the following wild card method names are matched and the output is modified in order to handle relationships eg. `/api/posts/1/comments`\n- `__get__.*`\n- `__findRelationships__.*`\n\nThe default behavior is to modify (deserialize from JSON API) the input to the following CRUD methods on all models:\n- `create`\n- `updateAttributes`\n\n### include\nAllows whitelisting of methods.\nDefine an array of whitelist objects. Whitelist objects can contain a \"methods\" key\nor both a \"models\" key and a \"methods\" key. If just the \"methods\" key is defined then\nthe methods specified will be serialized or deserialized using JSON API on all models that have\nthe specified methods. If a combination of\n\"model\" and \"methods\" keys are used then the specific combination of model and methods\nspecified will be serialized or deserialized using JSON API.\n\nNote: objects returned from a remote method that will be JSON API serialized MUST include\nan id property. id property can be null.\n\n#### example\n```js\n{\n  ...\n  \"include\": [\n    {\"methods\": \"customMethod\"},\n    {\"model\": \"post\", \"methods\": \"customMethod\"},\n    {\"model\": \"person\", \"methods\": [\"customMethod1\", \"customMethod2\"]}\n  ],\n  ...\n}\n```\n\n- Type: `array`\n- Default: `null`\n\n### hideIrrelevantMethods\nBy default, `loopback-component-jsonapi` disables a number of methods from each endpoint\nthat are not JSON API relevant. These methods are:\n- `upsert`\n- `exists`\n- `findOne`\n- `count`\n- `createChangeStream`\n- `updateAll`\n\nYou can use this option to prevent `loopback-component-jsonapi` from doing so. These methods are not modified by the component. Their output\nwill not be in a JSON API compliant format.\n\n#### example\n```js\n{\n  ...\n  \"hideIrrelevantMethods\": true,\n  ...\n}\n```\n\n- Type: `boolean`\n- Default: `true`\n\n### attributes\nBy default, model properties will be converted to attributes in JSON API terms.\nAll model properties except the primary key and any foreign keys will be copied into\nthe attributes object before output. If you wish to limit which properties will\nbe output as attributes you can specify a whitelist of attributes for each type.\n\n#### example\n```js\n{\n  ...\n  \"attributes\": {\n    \"posts\": [\"title\", \"content\"],\n    \"comments\": [\"createdAt\", \"updatedAt\", \"comment\"]\n  }\n  ...\n}\n```\n\n- Type: `object`\n- Default: `null`\n\n#### note\nThe attributes arrays are keyed by type not by model name. Type is the term used by JSON API to describe the resource type in question and while not required by JSON API it is usually plural. In `loopback-component-jsonapi` it is whatever the models `plural` is set to in `model.json`. So in our example above we defined: `\"posts\": [\"title\", \"content\"]` as the resource type for the `post` model is `posts`\n\n### foreignKeys\nAllows configuration of whether the component should expose foreign keys (which the jsonapi spec considers\nimplementation details) from the attributes hash.\n\n#### examples\n\nAlways expose foreign keys for all models\n```js\n{\n  ...\n  foreignKeys: true,\n  ...\n}\n```\n\nNever expose foreign keys for any models (default behaviour)\n```js\n{\n  ...\n  foreignKeys: false,\n  ...\n}\n```\n\nOnly expose foreign keys for the comment model\n```js\n{\n  ...\n  foreignKeys: [\n    {model: 'comment'}\n  ],\n  ...\n}\n```\n\nOnly expose foreign keys for the comment model findById method. eg. `GET /api/comments/1`\n```js\n{\n  ...\n  foreignKeys: [\n    {model: 'comment', method: 'findById'}\n  ],\n  ...\n}\n```\n\n- Type: `boolean|array`\n- Default: `false`\n\n## Custom remote methods\n\n### `jsonapi` remote method options\nSometimes you need to be able to control when a custom remote method should be handled by the component. By default, `loopback-component-jsonapi` will not handle (serialize or deserialize) custom remote methods. In order to tell the component to handle a custom remote method, you have the following options (In priority order):\n\n1. Set `jsonapi` to `true` when defining a custom remote method.\n2. Add the methods name to the component's `exclude` array setting. (see above)\n3. Add the methods name to the component's `include` array setting. (see above)\n4. Set `handleCustomRemoteMethods` to `true` in the component's settings. (see above)\n\nThis option takes precedence and sets the component to handle or not handle the custom remote method.\n\n#### examples\n```js\nPost.remoteMethod('greet', {\n  jsonapi: true\n  returns: { root: true }\n})\n```\nEnsures that the response from Post.greet will follow JSONApi format.\n\n```js\nPost.remoteMethod('greet', {\n  jsonapi: false\n  returns: { arg: 'greeting', type: 'string' }\n})\n```\nEnsures that the response from Post.greet will never follow JSONApi format.\n\n#### Note\nYou must always pass `root: true` to the `returns` object when using `loopback-component-jsonapi`. This is especialy important when you expect the response to be an array.\n\n### Overriding serialization type\nWhen `loopback-component-jsonapi` serializes a custom remote method, by default it will assume that the data being serialized is of the same type as the model the custom remote method is being defined on. Eg. For a remote method on a `Comment` model, it will be assumed that the data being returned from the remote method will be a comment or an array of comments. When this is not the case, you will need to set the type property in the `returns` object in the remote method definition.\n\n*If an unknown type or no type are given, the model name will be used.*\n\n#### example\n\n```js\nPost.remoteMethod('prototype.ownComments', {\n  jsonapi: true\n  returns: { root: true, type: 'comment' }\n})\n```\n\n## Custom Serialization\nFor occasions where you need greater control over the serialization process, you can implement a custom serialization function for each model as needed. This function will be used instead of the regular serialization process.\n\n#### example\n```js\nmodule.exports = function (MyModel) {\n  MyModel.jsonApiSerialize = function (options, callback) {\n    // either return an error\n    var err = new Error('Unable to serialize record');\n    err.status = 500;\n    cb(err)\n\n    // or return serialized records\n    if (Array.isArray(options.records)) {\n      // serialize an array of records\n    } else {\n      // serialize a single record\n    }\n    cb(null, options);\n  }\n}\n```\n\n##### function parameters\n\n- `options` All config options set for the serialization process.\n- `callback` Callback to call with error or serialized records\n\n## Custom Deserialization\nFor occasions where you need greater control over the deserialization process, you can implement a custom deserialization function for each model as needed. This function will be used instead of the regular deserialization process.\n\n#### example\n```js\nmodule.exports = function (MyModel) {\n  MyModel.jsonApiDeserialize = function (options, callback) {\n    // either return an error\n    var err = new Error('Unable to deserialize record');\n    err.status = 500;\n    cb(err)\n\n    // or\n    // options.data is the raw data\n    // options.result needs to be populated with deserialization result\n    options.result = options.data.data.attributes;\n\n    cb(null, options);\n  }\n}\n```\n\n## Custom Errors\nGeneric errors respond with a 500, but sometimes you want to have a better control over the error that is returned to the client, taking advantages of fields provided by JSONApi.\n\n**It is recommended that you extend the base Error constructor before throwing errors. Eg. BadRequestError**\n\n`meta` and `source` fields needs to be objects.\n\n#### example\n```js\nmodule.exports = function (MyModel) {\n  MyModel.find = function () {\n    var err = new Error('April 1st, 1998');\n    \n    err.status = 418;\n    err.name = 'I\\'m a teapot';\n    err.source = { model: 'Post', method: 'find' };\n    err.detail = 'April 1st, 1998';\n    err.code = 'i\\'m a teapot';\n    err.meta = { rfc: 'RFC2324' };\n\n    throw err\n  }\n}\n\n// This will be returned as :\n// {\n//   errors: [\n//     {\n//       status: 418,\n//       meta: { rfc: 'RFC2324' },\n//       code: 'i\\'m a teapot',\n//       detail: 'April 1st, 1998',\n//       title: 'I\\'m a teapot',\n//       source: { model: 'Post', method: 'find' }\n//     }\n//   ]\n// }\n```\n\n##### function parameters\n\n- `options` All config options set for the deserialization process.\n- `callback` Callback to call with error or serialized records\n\n## The options object\n\n###### `options.type`\nResource type. Originally calculated from a models plural. Is used in the default\nserialization process to set the type property for each model in a JSON API response.\n- eg. `posts`\n\n###### `options.method`\nThe method that was called to get the data for the current request. This is not\nused in the serialization process but is provided for custom hook and serialization\ncontext.\n- Eg. `create`, `updateAttributes`\n\n###### `options.primaryKeyField`\nThe name of the property that is the primary key for the model. This is usually just\n`id` unless defined differently in a model.json file.\n\n###### `options.requestedIncludes`\nThe relationships that the user has requested be side loaded with the request.\nFor example, for the request `GET /api/posts?include=comments` options.requestedIncludes\nwould be `'comments'`.\n- Type: `string` or `array`\n- eg: `'comments'` or `['posts', 'comments']`\n\n###### `options.host`\nThe host part of the url including any port information.\n- eg. `http://localhost:3000`\n\n###### `options.restApiRoot`\nThe api prefix used before resource information. Can be used in conjunction with\n`options.host` and `options.type` to build up the full url for a resource.\n- eg. `/api`\n\n###### `options.topLevelLinks`\nLinks object used at the top level of the JSON API response structure.\n- eg. `{links: {self: 'http://localhost:3000/api/posts'}}`\n\n###### `options.dataLinks`\nLinks object used to generate links for individual resource items. The structure is\nand object with JSON API link keys such as `self` or `related` that are defined as\na function that will be called for each resource.\n\nEg.\n```js\noptions.dataLinks: {\n  self: function (resource) {\n    return 'http://localhost:3000/posts/' + resource.id;\n  }\n}\n```\nAs shown above, each resource gets passed to the function and the result of the\nfunction is assigned to the key in the final JSON API response.\n\n###### `options.relationships`\nThis contains all the relationship definitions for the model being serialized.\nRelationship definition objects are in the same format as in loopback's `Model.relations`\ndefinition. An object with relationship name keys, each having properties:\n\n- `modelTo` loopback model object\n- `keyTo` name of key on to model\n- `modelFrom` loopback model object\n- `keyFrom` name of key on from model\n- `type` type of relationship (belongsTo, hasOne, hasMany)\n\nThis information is used to build relationship urls and even setup side-loaded\ndata correctly during the serialization process.\n\neg.\n```js\noptions.relationships = {\n  comments: { modelTo: ...etc },\n  tags: { modelTo: ...etc }\n}\n```\n\n###### `options.results`\nThis is the actual data to be serialized. In `beforeJsonApiSerialize` and\n`jsonApiSerialize` this will be the raw data as you would ordinarily get it from\nloopback. In `afterJsonApiSerialize` this will be the serialized data ready for\nany final modifications.\n\n###### `options.exclude`\nThis is the exclude settings as defined in the `exclude` configuration option\nexplained earlier. Use this in `beforeJsonApiSerialize` to make any model specific\nadjustments before serialization.\n\n###### `options.attributes`\nThis is the attributes settings as defined in the `attributes` configuration option\nexplained earlier. Use this in `beforeJsonApiSerialize` to make any model specific\nadjustments before serialization.\n\n###### `options.data`\nThe raw body data prior to deserialization from creates and updates. This can be\nmanipulated prior to deserialization using `beforeJsonApiDeserialize`\n\n###### `options.result`\nThe deserialized raw body data. This is used when saving\nmodels as part of a create or update operation. You can manipulate this prior to\nthe save occuring in `afterJsonApiDeserialize`\n\n## Serialization/Deserialization Hooks\nFor occasions when you don't want to fully implement (de)serialization for a model manually but\nyou need to manipulate the serialization/deserialization process, you can use the\nhooks `beforeJsonApiSerialize`, `afterJsonApiSerialize`, `beforeJsonApiDeserialize` and `afterJsonApiDeserialize`.\n\n### beforeJsonApiDeserialize\nIn order to modify the deserialization process on a model by model basis, you can\ndefine a `Model.beforeJsonApiDeserialize` function as shown below. The function\nwill be called with an options object and a callback which must be called with either\nan error as the first argument or the modified options object as the second\nparameter.\n\n**Examples of things you might want to use this feature for**\n- modifying `options.data.data.attributes` prior to their being deserialized into model properties that\nwill be saved\n- modifying `options.data.data.relationships` prior to their being used to save relationship linkages\n\n#### code example\n```js\nmodule.exports = function (MyModel) {\n  MyModel.beforeJsonApiDeserialize = function (options, callback) {\n    // either return an error\n    var err = new Error('Unwilling to deserialize record');\n    err.status = 500;\n    callback(err)\n\n    // or return modified data\n    options.data.data.attributes.title = 'modified title';\n\n    // returned options.data will be deserialized by either the default deserialization process\n    // or by a custom deserialize function if one is present on the model.\n    callback(null, options);\n  }\n}\n```\n\n### afterJsonApiDeserialize\nThis function will be called with an options object and a callback which must be called with either\nan error as the first argument or the modified options object as the second parameter.\n\n**Examples of things you might want to use this feature for**\n- modifying `options.result` after their having being deserialized from `options.data.data.attributes`\n- modifying `options.data.data.relationships` prior to their being used to save relationship linkages\n\n#### code example\n```js\nmodule.exports = function (MyModel) {\n  MyModel.afterJsonApiDeserialize = function (options, callback) {\n    // either return an error\n    var err = new Error('something went wrong!');\n    err.status = 500;\n    callback(err)\n\n    // or return modified data prior to model being saved with options.result\n    options.result.title = 'modified title';\n\n    callback(null, options);\n  }\n}\n```\n\n##### function parameters\n- `options` All config options set for the deserialization process. See the \"the options object\"\nsection above for info on what options properties are available for modification.\n- `callback` Callback to call with error or options object.\n\n### beforeJsonApiSerialize\nIn order to modify the serialization process on a model by model basis, you can\ndefine a `Model.beforeJsonApiSerialize` function as shown below. The function\nwill be called with an options object and a callback which must be called with either\nan error as the first argument or the modified options object as the second\nparameter.\n\n**Examples of things you might want to use this feature for**\n- modify the record(s) before serialization by modifying `options.results`\n- modify the resource type by modifying `options.type`\n- setup serialization differently depending on `options.method`\n- side load data (advanced)\n- modify the way relationships are serialized\n\n#### code example\n```js\nmodule.exports = function (MyModel) {\n  MyModel.beforeJsonApiSerialize = function (options, callback) {\n    // either return an error\n    var err = new Error('Unable to serialize record');\n    err.status = 500;\n    callback(err)\n\n    // or return modified records\n    if (Array.isArray(options.results)) {\n      // modify an array of records\n    } else {\n      // modify a single record\n    }\n    // returned options.records will be serialized by either the default serialization process\n    // or by a custom serialize function (described above) if one is present on the model.\n    callback(null, options);\n  }\n}\n```\n\n##### function parameters\n- `options` All config options set for the serialization process. See the \"function parameters\"\nsection above for info on what options properties are available for modification.\n- `callback` Callback to call with error or options object.\n\n#### example use case\nBecause the `beforeJsonApiSerialize` method is passed all the options that will\nbe used during serialization, it is possible to tweak options to affect the\nserialization process. One example of this is modifying the `type` option to\nchange the resource type that will be output.\n\n```js\nmodule.exports = function (MyModel) {\n  MyModel.beforeJsonApiSerialize = function (options, callback) {\n    options.type = 'mycustommodels';\n    cb(null, options);\n  }\n}\n```\n\n### afterJsonApiSerialize\nIn order to modify the serialized data on a model by model basis, you can\ndefine a `Model.afterJsonApiSerialize` function as shown below. The function\nwill be called with an options object and a callback which must be called with either\nan error as the first argument or the modified options object as the second\nparameter.\n\n#### example\n```js\nmodule.exports = function (MyModel) {\n  MyModel.afterJsonApiSerialize = function (options, callback) {\n    // either return an error\n    var err = new Error('Unable to modify serialized record');\n    err.status = 500;\n    callback(err)\n\n    // or return modified records\n    if (Array.isArray(options.results)) {\n      // modify an array of serialized records\n    } else {\n      // modify a single serialized record\n    }\n    // returned options.records will be output through the api.\n    callback(null, options);\n  }\n}\n```\n\n##### function parameters\n- `options` All config options set for the serialization process\n- `callback` Callback to call with modified serialized records\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigitalsadhu%2Floopback-component-jsonapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdigitalsadhu%2Floopback-component-jsonapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigitalsadhu%2Floopback-component-jsonapi/lists"}