ts-japi icon indicating copy to clipboard operation
ts-japi copied to clipboard

[BUG] Related fields are included in attributes by default

Open egmacke opened this issue 1 year ago • 7 comments

Describe the bug*

When serializing a complex object with defined relationships, all related fields are included in the attributes by default as well as in relationships.

To avoid this, you currently have to explicitly define a projection that excludes the relationship fields which adds an unnecessary overhead.

To Reproduce*

See replit: https://replit.com/@egmacke/ts-japi-issue-76

Result is

{
  "jsonapi": {
    "version": "1.0"
  },
  "data": {
    "type": "User",
    "id": "1",
    "attributes": {
      "name": "Foo",
      "articles": [
        {
          "id": "1",
          "title": "Article 1",
          "body": "Article 1 body"
        },
        {
          "id": "2",
          "title": "Article 2",
          "body": "Article 2 body"
        }
      ]
    },
    "relationships": {
      "articles": {
        "data": [
          {
            "type": "Article",
            "id": "1"
          },
          {
            "type": "Article",
            "id": "2"
          }
        ]
      }
    }
  }
}

I would expect the result to be (which can be achieved using the serializer option {projection: {articles: 0}})

{
  "jsonapi": {
    "version": "1.0"
  },
  "data": {
    "type": "User",
    "id": "1",
    "attributes": {
      "name": "Foo",
    },
    "relationships": {
      "articles": {
        "data": [
          {
            "type": "Article",
            "id": "1"
          },
          {
            "type": "Article",
            "id": "2"
          }
        ]
      }
    }
  }
}

Expected behavior*

When a relator is defined for a given field, it should be automatically excluded from the serialized attributes.

egmacke avatar Mar 21 '24 17:03 egmacke

@jun-sheaf I'm happy to work on a solution for this unless you think there's a reason not to?

egmacke avatar Mar 21 '24 17:03 egmacke

This could be a breaking change I guess? The question is whether the opposite of the default is what's expected from users. I think we can maybe have a global function that changes the default. We can expose it as a named export in the main module.

jrandolf avatar Mar 21 '24 20:03 jrandolf

@jun-sheaf in order to reduce impact on library users that expect the current behaviour, I'd suggest maybe having a new serializer option - something like excludeRelationshipsFromAttributes which if unset defaults to false, but if unset, it logs a deprecation warning that the default value for this will be changed in future versions (next major version perhaps)?

egmacke avatar Mar 25 '24 08:03 egmacke

Let's add the option, but without the deprecation notice.

Edit: Actually, scratch that. Do what you feel as the active maintainer.

jrandolf avatar Mar 25 '24 09:03 jrandolf

Having investigated this further, I've actually found a simpler way to solve this issue.

Rather than making changes to the library, there's a way using core javascript/typescript which solves it.

For any fields that should only be serialized as relationships, defining the property on the data model as true private (using the # notation - ref) then providing a public accessor function (either a method or a getter) prevents the library from seeing the property during serialization.

The property can then be accessed in the relator definition via the method or getter.

I'll create a PR to update the documentation to recommend this approach instead of making code changes.

egmacke avatar Mar 26 '24 15:03 egmacke