mathematic-inc / ts-japi

A highly-modular (typescript-friendly)-framework agnostic library for serializing data to the JSON:API specification
Apache License 2.0
203 stars 16 forks source link

[BUG] Multiple relationships on the same type do not get included by the serializer #42

Closed egmacke closed 2 years ago

egmacke commented 2 years ago

Describe the bug

Given this model

class Article {
  public content: string;
  public author: User;
  public reviewer: User;
}

The expected behaviour when serialising, using relations for the User objects, would be to have multiple relationships containing the type and id for the User.

However, only a single User entry is added. I believe this is because the serializer collectionName field is used as the key for the relationships, which means only one relationship of any given type can ever be serialized.

To Reproduce

The following code snippet produces the error:

class User {
  public id: string;

  public constructor(public name: string) {
    this.id = name;
  }
}

class Article {
  public id: string;

  public content: string;

  public author: User;

  public reviewer: User;

  public constructor() {
    this.id = 'id';
    this.content = 'loreum ipsum';
    this.author = new User('Alice');
    this.reviewer = new User('Bob');
  }
}

const UserSerializer = new Serializer<User>('User');

const TestUser1Relator = new Relator<Article, User>(async (test) => test.author, UserSerializer);

const TestUser2Relator = new Relator<Article, User>(async (test) => test.reviewer, UserSerializer);

const TestSerializer = new Serializer<Article>('Test', {
  relators: [TestUser1Relator, TestUser2Relator],
  projection: {
    author: 0,
    reviewer: 0,
  },
});

void (async () => {
  TestUser1Relator.relatedName;
  const testDto = new Article();

  const result = await TestSerializer.serialize(testDto);
  console.log(JSON.stringify(result));
})();

Output:

{
  "jsonapi": { "version": "1.0" },
  "data": {
    "type": "Test",
    "id": "id",
    "attributes": { "content": "loreum ipsum" },
    "relationships": { "User": { "data": { "type": "User", "id": "Bob" } } }
  }
}

Expected behavior

Expected output should be something like:

{
  "jsonapi": { "version": "1.0" },
  "data": {
    "type": "Test",
    "id": "id",
    "attributes": { "content": "loreum ipsum" },
    "relationships": {
      "author": { "data": { "type": "User", "id": "Alice" } },
      "reviewer": { "data": { "type": "User", "id": "Bob" } }
    }
  }
}

Platform

Proposed solution

By extending the RelatorOptions object to include an optional relatedName field, the serialization can use this if provided as the keys for the relationships object.