Skip to content

Vandal UI hangs when related data is part of main data in JSON:API response (no 'included' present) #14

@michel3141

Description

@michel3141

Summary

Vandal UI does not correctly resolve relationships when the related resource is already present in the top-level data array, instead of being included in the included section. This behavior causes the UI to hang and fail silently.

Minimal Reproduction

app/models/item.rb

class Item < ApplicationRecord
  belongs_to :previous, class_name: "Item", optional: true
end

app/resources/item_resource.rb

class ItemResource < ApplicationResource
  attribute :label, :string
  attribute :previous_id, :integer

  belongs_to :previous, resource: ItemResource
end

Sample data

a = Item.create(label: "first")
b = Item.create(label: "second", previous: a)

Test case

curl "http://localhost:3000/api/v1/items?include=previous"

Returns:

{
  "data": [
    {
      "id": "1",
      "type": "items",
      "attributes": {
        "label": "first",
        "previous_id": null
      },
      "relationships": {
        "previous": {
          "links": {
            "related": null
          },
          "data": null
        }
      }
    },
    {
      "id": "2",
      "type": "items",
      "attributes": {
        "label": "second",
        "previous_id": 1
      },
      "relationships": {
        "previous": {
          "links": {
            "related": "change_me_in/config/environments:3000/api/v1/items/1"
          },
          "data": {
            "type": "items",
            "id": "1"
          }
        }
      }
    }
  ],
  "meta": {}
}

Proposed Fix

diff --git a/src/response-table.ts b/src/response-table.ts
index 84bbf15..b382d07 100644
--- a/src/response-table.ts
+++ b/src/response-table.ts
@@ -123,7 +123,7 @@ export class ResponseTable {
   private _buildRelationshipNode(jsonRel) {
     let allNodes = this.json.data
     if (!Array.isArray(allNodes)) allNodes = [allNodes]
-    allNodes = allNodes.concat(this.json.included)
+    allNodes = allNodes.concat(this.json.included || [])
     let node = allNodes.filter((n: any) => {
       return n.type === jsonRel.type && n.id === jsonRel.id
     })[0]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions