mrichar1 / jsonapi-vuex Goto Github PK
View Code? Open in Web Editor NEWUse a JSONAPI api with a Vuex store, with data restructuring/normalization.
License: GNU Affero General Public License v3.0
Use a JSONAPI api with a Vuex store, with data restructuring/normalization.
License: GNU Affero General Public License v3.0
Should the included records be processed not only for the get action but for the others? I have a use case where I send a POST and some included records come back. However they are not found in return value from the action because the included
records are not processed for this action.
Hi Matthew!
I'm getting the "RangeError: Maximum call stack size exceeded" error when trying to do:
this.$store
.dispatch('jv/get', [
`products/similar_products`,
{
params: {
magentoProductId: this.product._id,
include: 'supplier'
}
}
])
{
"links": {
"self": "/api/products/similar_products?magentoProductId=1\u0026include=supplier"
},
"meta": { "totalItems": 28 },
"data": [
{
"id": "6201",
"type": "Product",
"attributes": {
"_id": 6201,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-07-04T13:24:44+00:00",
"createdAt": "2018-04-09T10:14:11+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "112" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "18737",
"type": "Product",
"attributes": {
"_id": 18737,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": false,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-01-08T14:55:49+00:00",
"createdAt": "2018-04-10T07:07:13+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "34" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "20884",
"type": "Product",
"attributes": {
"_id": 20884,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": false,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2018-04-10T09:23:33+00:00",
"createdAt": "2018-04-10T08:44:37+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "65" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "40642",
"type": "Product",
"attributes": {
"_id": 40642,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": false,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-06-05T14:57:48+00:00",
"createdAt": "2018-08-27T07:26:55+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "154" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "42685",
"type": "Product",
"attributes": {
"_id": 42685,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-07-10T07:28:52+00:00",
"createdAt": "2018-09-04T07:45:23+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "155" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "32089",
"type": "Product",
"attributes": {
"_id": 32089,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-04-15T16:16:27+00:00",
"createdAt": "2018-04-11T13:25:38+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "126" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "2528",
"type": "Product",
"attributes": {
"_id": 2528,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-07-04T13:58:21+00:00",
"createdAt": "2018-04-09T09:23:35+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "21" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "19782",
"type": "Product",
"attributes": {
"_id": 19782,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-06-25T07:27:42+00:00",
"createdAt": "2018-04-10T07:24:54+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "133" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "37062",
"type": "Product",
"attributes": {
"_id": 37062,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2018-06-04T16:28:19+00:00",
"createdAt": "2018-06-04T16:28:19+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "100" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "56377",
"type": "Product",
"attributes": {
"_id": 56377,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-05-22T14:39:51+00:00",
"createdAt": "2019-05-22T14:39:51+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "178" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "11602",
"type": "Product",
"attributes": {
"_id": 11602,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-04-15T14:34:59+00:00",
"createdAt": "2018-04-09T15:13:28+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "63" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "51495",
"type": "Product",
"attributes": {
"_id": 51495,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-07-04T14:15:23+00:00",
"createdAt": "2019-04-15T15:06:52+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "9" } },
"magentoProducts": {
"data": [{ "type": "MagentoProduct", "id": "1558" }]
}
}
},
{
"id": "14539",
"type": "Product",
"attributes": {
"_id": 14539,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-06-25T07:28:23+00:00",
"createdAt": "2018-04-09T15:57:05+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "102" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "54266",
"type": "Product",
"attributes": {
"_id": 54266,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-05-22T14:05:37+00:00",
"createdAt": "2019-05-22T13:41:39+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "175" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "50962",
"type": "Product",
"attributes": {
"_id": 50962,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": false,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-07-04T13:24:40+00:00",
"createdAt": "2019-04-15T14:53:43+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "112" } }
}
},
{
"id": "6480",
"type": "Product",
"attributes": {
"_id": 6480,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-07-04T13:24:44+00:00",
"createdAt": "2018-04-09T10:14:11+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "112" } }
}
},
{
"id": "18374",
"type": "Product",
"attributes": {
"_id": 18374,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": false,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2018-05-03T12:10:22+00:00",
"createdAt": "2018-04-10T07:07:13+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "34" } },
"magentoProducts": {
"data": [{ "type": "MagentoProduct", "id": "1506" }]
}
}
},
{
"id": "25649",
"type": "Product",
"attributes": {
"_id": 25649,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-07-04T14:15:23+00:00",
"createdAt": "2018-04-10T14:23:51+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "9" } }
}
},
{
"id": "51376",
"type": "Product",
"attributes": {
"_id": 51376,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": false,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-06-05T14:57:48+00:00",
"createdAt": "2019-04-15T15:03:57+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "154" } }
}
},
{
"id": "58028",
"type": "Product",
"attributes": {
"_id": 58028,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-07-10T07:28:52+00:00",
"createdAt": "2019-06-11T12:57:31+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "155" } }
}
},
{
"id": "51771",
"type": "Product",
"attributes": {
"_id": 51771,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-06-25T07:28:41+00:00",
"createdAt": "2019-04-15T15:23:23+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "102" } },
"magentoProducts": {
"data": [{ "type": "MagentoProduct", "id": "1558" }]
}
}
},
{
"id": "37813",
"type": "Product",
"attributes": {
"_id": 37813,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-06-25T07:28:24+00:00",
"createdAt": "2018-06-05T13:39:53+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "102" } }
}
},
{
"id": "52327",
"type": "Product",
"attributes": {
"_id": 52327,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-06-25T07:29:00+00:00",
"createdAt": "2019-04-15T16:05:41+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "33" } }
}
},
{
"id": "56321",
"type": "Product",
"attributes": {
"_id": 56321,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-05-22T14:39:51+00:00",
"createdAt": "2019-05-22T14:39:51+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "178" } },
"magentoProducts": {
"data": [{ "type": "MagentoProduct", "id": "2915" }]
}
}
},
{
"id": "4003",
"type": "Product",
"attributes": {
"_id": 4003,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-07-05T07:20:21+00:00",
"createdAt": "2018-04-09T09:58:23+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "4" } },
"magentoProducts": { "data": [{ "type": "MagentoProduct", "id": "1" }] }
}
},
{
"id": "58403",
"type": "Product",
"attributes": {
"_id": 58403,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "CHF",
"baseCurrency": "EUR",
"isInStock": true,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-07-05T07:20:21+00:00",
"createdAt": "2019-07-05T07:20:21+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "4" } }
}
},
{
"id": "22244",
"type": "Product",
"attributes": {
"_id": 22244,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": false,
"isVermouth": false,
"hasMatches": true,
"updatedAt": "2019-04-15T16:05:21+00:00",
"createdAt": "2018-04-10T13:39:12+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "33" } },
"magentoProducts": {
"data": [{ "type": "MagentoProduct", "id": "2915" }]
}
}
},
{
"id": "57859",
"type": "Product",
"attributes": {
"_id": 57859,
"sku": "111111",
"name": "name",
"alcohol": 40,
"size": 70,
"price": 10,
"basePrice": 12,
"currency": "",
"baseCurrency": "",
"isInStock": true,
"isVermouth": false,
"hasMatches": false,
"updatedAt": "2019-06-25T07:29:07+00:00",
"createdAt": "2019-06-05T14:33:58+00:00"
},
"relationships": {
"supplier": { "data": { "type": "Supplier", "id": "33" } }
}
}
],
"included": [
{
"id": "112",
"type": "Supplier",
"attributes": {
"_id": 112,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:30+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "34",
"type": "Supplier",
"attributes": {
"_id": 34,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:22+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "65",
"type": "Supplier",
"attributes": {
"_id": 65,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:25+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "154",
"type": "Supplier",
"attributes": {
"_id": 154,
"code": "code",
"name": "name",
"createdAt": "2018-08-27T06:51:52+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "155",
"type": "Supplier",
"attributes": {
"_id": 155,
"code": "code",
"name": "name",
"createdAt": "2018-09-04T06:57:40+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "126",
"type": "Supplier",
"attributes": {
"_id": 126,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:31+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "21",
"type": "Supplier",
"attributes": {
"_id": 21,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:20+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "133",
"type": "Supplier",
"attributes": {
"_id": 133,
"code": "code",
"name": "name",
"createdAt": "2018-04-10T07:16:58+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "100",
"type": "Supplier",
"attributes": {
"_id": 100,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:29+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "178",
"type": "Supplier",
"attributes": {
"_id": 178,
"code": "code",
"name": "name",
"createdAt": "2019-05-21T18:09:29+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "63",
"type": "Supplier",
"attributes": {
"_id": 63,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:25+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "9",
"type": "Supplier",
"attributes": {
"_id": 9,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:19+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "102",
"type": "Supplier",
"attributes": {
"_id": 102,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:29+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "175",
"type": "Supplier",
"attributes": {
"_id": 175,
"code": "code",
"name": "name",
"createdAt": "2019-05-21T18:06:47+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "33",
"type": "Supplier",
"attributes": {
"_id": 33,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:22+00:00",
"isDomestic": false,
"currency": "EUR"
}
},
{
"id": "4",
"type": "Supplier",
"attributes": {
"_id": 4,
"code": "code",
"name": "name",
"createdAt": "2018-04-06T08:58:19+00:00",
"isDomestic": false,
"currency": "EUR"
}
}
]
}
Any idea what is happening?
I'm seeing an issue with circular references in the latest version of the library. My circular reference looks like this:
obj.coupons.766914981.menus.715597942.bundles.427576225.items.710494120.sellable.item = obj.coupons.766914981.menus.715597942.bundles.427576225.items.710494120 = [object Object]
In other words, items.710494120.sellable.item === items.710494120
I think it's possible that this could be something to do with the way we are unpacking the recursive relationships.
The JSON payload for this resource looks like this:
{
"data": {
"attributes": {
...
},
"id": "...",
"relationships": {
"bundles": {
"data": [
{
"id": "7674405",
"type": "bundle"
},
{
"id": "427576225",
"type": "bundle"
}
]
},
"coupons": {
"data": [
{
"id": "766914981",
"type": "coupon"
},
{
"id": "884957217",
"type": "coupon"
}
]
},
"items": {
"data": [
{
"id": "432264256",
"type": "item"
},
{
"id": "710494120",
"type": "item"
}
]
},
"menus": {
"data": [
{
"id": "715597942",
"type": "menu"
},
{
"id": "867072458",
"type": "menu"
}
]
},
"todos": {
"data": [
{
"id": "410273406",
"type": "todo"
},
{
"id": "24975302",
"type": "todo"
},
{
"id": "913975121",
"type": "todo"
},
{
"id": "673100534",
"type": "todo"
},
{
"id": "521765479",
"type": "todo"
},
{
"id": "101766111",
"type": "todo"
}
]
}
},
"type": "user"
},
"included": [
{
"attributes": {
...
},
"id": "766914981",
"relationships": {
"bundles": {
"data": []
},
"items": {
"data": []
},
"menus": {
"data": [
{
"id": "715597942",
"type": "menu"
}
]
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "coupon"
},
{
"attributes": {
...
},
"id": "884957217",
"relationships": {
"bundles": {
"data": []
},
"items": {
"data": []
},
"menus": {
"data": []
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "coupon"
},
{
"attributes": {
...
},
"id": "7674405",
"relationships": {
"items": {
"data": [
{
"id": "432264256",
"type": "item"
},
{
"id": "710494120",
"type": "item"
}
]
},
"sales": {
"data": []
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "bundle"
},
{
"attributes": {
...
},
"id": "427576225",
"relationships": {
"items": {
"data": [
{
"id": "432264256",
"type": "item"
},
{
"id": "710494120",
"type": "item"
}
]
},
"sales": {
"data": [
{
"id": "710541635",
"type": "sale"
}
]
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "bundle"
},
{
"attributes": {
...
},
"id": "715597942",
"relationships": {
"bundles": {
"data": [
{
"id": "7674405",
"type": "bundle"
},
{
"id": "427576225",
"type": "bundle"
}
]
},
"items": {
"data": [
{
"id": "432264256",
"type": "item"
}
]
},
"sales": {
"data": [
{
"id": "492646868",
"type": "sale"
}
]
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "menu"
},
{
"attributes": {
...
},
"id": "867072458",
"relationships": {
"bundles": {
"data": [
{
"id": "427576225",
"type": "bundle"
}
]
},
"items": {
"data": [
{
"id": "710494120",
"type": "item"
}
]
},
"sales": {
"data": []
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "menu"
},
{
"attributes": {
...
},
"id": "432264256",
"relationships": {
"item": {
"data": {
"id": "432264256",
"type": "item"
}
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "bar"
},
{
"id": "432264256",
"relationships": {
"sales": {
"data": []
},
"sellable": {
"data": {
"id": "432264256",
"type": "bar"
}
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "item"
},
{
"attributes": {
...
},
"id": "710494120",
"relationships": {
"item": {
"data": {
"id": "710494120",
"type": "item"
}
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "foo"
},
{
"id": "710494120",
"relationships": {
"sales": {
"data": [
{
"id": "710541635",
"type": "sale"
}
]
},
"sellable": {
"data": {
"id": "710494120",
"type": "foo"
}
},
"user": {
"data": {
"id": "1061808648",
"type": "user"
}
}
},
"type": "item"
}
]
}
Is there a recommended way to get the relationship resources of a certain parent resource? They can be fetched from the server with the getRelated method, but I can't find if there is a getter to get the fetched relations from the store.
It can be done with jsonPath syntax, e.g.:
this.$store.getters['jv/get']('contactperson', '$[?(@._jv.relationships.customer.data.id=="' + this.customerId + '")]')
but this looks a bit rough for such a trivial task.
By the way, the jsonPath examples for filtering in the readme seem to be missing the '$' operator.
I'm feeding a data-table straight from the store with the get
getter. Am I correct that it's not possible to entirely replace a type with an API response? Could not find anything in the source so I wrote my own mutation for this but would like to clear the previous results once the promise gets resolved, not before the API is called. This could be useful for server-side search results.
Another option I'm considering is to just store the search results separately and use these when in search mode.
Curious how other people are approaching this.
When dispatching jv/patch
actions I am getting a status 400
. The generated payload looks good, and I have compared it to the json shown at the official json api website: https://jsonapi.org/format/#crud-updating.
The server I have implemented is on Rails, and has been around for quite a while with a lot of traction: https://github.com/cerebris/jsonapi-resources.
After doing some investigation, it appears the presence of the links
is what is causing these PATCH requests to fail. I am not positive if these links should be present in PATCH requests or not, but removing them would most likely conform to more JSON Api server implementations out there.
When I use the following code:
this.$store.commit('foo');
export default new Vuex.Store({
state: {
wut: false,
},
mutations: {
foo(state) {
state.wut = true;
},
},
modules: {
jv: jsonapiModule(Vue.axios),
},
});
I get this error:
vue.runtime.esm.js?2b0e:1887 RangeError: Maximum call stack size exceeded
at Function.keys (<anonymous>)
at _traverse (vue.runtime.esm.js?2b0e:2120)
at _traverse (vue.runtime.esm.js?2b0e:2122)
at _traverse (vue.runtime.esm.js?2b0e:2122)
at _traverse (vue.runtime.esm.js?2b0e:2122)
at _traverse (vue.runtime.esm.js?2b0e:2122)
at _traverse (vue.runtime.esm.js?2b0e:2122)
at _traverse (vue.runtime.esm.js?2b0e:2122)
at _traverse (vue.runtime.esm.js?2b0e:2122)
at _traverse (vue.runtime.esm.js?2b0e:2122)
I haven't found a cause yet but I will do more investigating.
When an action is currently dispatched, the data returned has the jv helpers added via addJvHelpers
. This returned data is then not possible to reuse in subsequent requests in a modified form because the library checks for the presence of the attrs
getter to determine if the data is user-submitted in normToJsonApiItem
:
// User-generated data (e.g. post) has no helper methods
if (data[jvtag].hasOwnProperty('attrs') && jvConfig.followRelationshipsData) {
jsonapi['attributes'] = data[jvtag].attrs
} else {
jsonapi['attributes'] = Object.assign({}, data)
delete jsonapi['attributes'][jvtag]
}
My current workaround is to strip the jv helpers before reusing the data in a subsequent post/patch.
Perhaps we could use a different kind of check for user-generated data since sometimes user-generated data might actually include the helpers?
I have an entity (Product) which has 2 relations (Manufacturer and Supplier)
Product to Manufacturer has ManyToMany relations and in JSON response is returned as array
Product to Supplier has ManyToOne relations and it is always an object.
After the followRelationships() method is executed I have wrongly mapped data.
The Manufacturer relation is mapped correctly, but for the Supplier it is an empty object.
Thanks in advance for your help
Add support for config options, overriding defaults when passed in when instantiating module.
See the warnings/errors in e.g. https://travis-ci.com/mrichar1/jsonapi-vuex/builds/104830295
We should look at the included
tag and add any included objects to the store.
Currently, it seems we have to pass an array to call dispatch with query params:
this.$store.dispatch('jv/get', ['widget/1', {params: params}]);
It would be slightly nicer if we could just call it like so:
this.$store.dispatch('jv/get', 'widget/1', { params: params });
Is there anything blocking us from modifying the API to receive non-array args?
It looks like this library uses this pattern frequently:
.catch((error) => {
return error
})
This makes it impossible to use something like this in Vue:
async beforeRouteEnter(to, from, next) {
try {
await store.dispatch('jv/get', `users/${username}`);
} catch (error) {
// TODO: Handle 404 here.
}
},
As a workaround, I have to check if the passed value is an Error object:
const response = await store.dispatch('jv/get', `users/${username}`);
if (response instanceof Error) {
// TODO: Handle 404 here.
}
I think a solution might be to just remove the .catch()
in the library to prevent swallowing errors. Or have the library check the status code to decide if it should catch the error or not.
Hi! If i use an action get
, I get this error in console
WARN Cannot stringify a function isRel
WARN Cannot stringify a function isAttr
{
"_jv": {
"type": "node--page",
"id": "d9e71e78-f50e-46f2-87b6-c7ebfbd37c08",
"relationships": {
"node_type": {
"data": {
"type": "node_type--node_type",
"id": "e48ba823-9d21-4c9e-beab-69d048908d70"
},
"links": {
"self": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08/relationships/node_type?resourceVersion=id%3A29"
},
"related": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08/node_type?resourceVersion=id%3A29"
}
}
},
"revision_uid": {
"data": {
"type": "user--user",
"id": "ff9767ae-fe0b-4bdf-ade6-514d92cac680"
},
"links": {
"self": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08/relationships/revision_uid?resourceVersion=id%3A29"
},
"related": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08/revision_uid?resourceVersion=id%3A29"
}
}
},
"uid": {
"data": {
"type": "user--user",
"id": "ff9767ae-fe0b-4bdf-ade6-514d92cac680"
},
"links": {
"self": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08/relationships/uid?resourceVersion=id%3A29"
},
"related": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08/uid?resourceVersion=id%3A29"
}
}
},
"sections": {
"data": [
{
"type": "paragraph--items",
"id": "e6b9e27c-0bfd-4f64-8e40-086e6d811a2e",
"meta": {
"target_revision_id": 89
}
},
{
"type": "paragraph--items",
"id": "e06a503b-b30d-46cd-aa4c-ba606fa0405c",
"meta": {
"target_revision_id": 93
}
}
],
"links": {
"self": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08/relationships/sections?resourceVersion=id%3A29"
},
"related": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08/sections?resourceVersion=id%3A29"
}
}
}
},
"links": {
"self": {
"href": "https://localhost/api/node/page/d9e71e78-f50e-46f2-87b6-c7ebfbd37c08?resourceVersion=id%3A29"
}
},
"isRel": {},
"isAttr": {}
},
"drupal_internal__nid": 1,
"drupal_internal__vid": 29,
"langcode": "ru",
"revision_timestamp": "2019-06-11T12:28:09+00:00",
"revision_log": null,
"status": true,
"title": "Ваша кредитная система",
"created": "2019-05-31T15:50:33+00:00",
"changed": "2019-06-11T12:28:09+00:00",
"promote": false,
"sticky": false,
"default_langcode": true,
"revision_translation_affected": null,
"metatag": null,
"path": null,
"body": null,
"subtitle": {
"value": "Title",
"format": "basic_html",
"processed": "Title"
},
"node_type": {},
"revision_uid": {},
"uid": {},
"sections": {}
}
And calling an action getRelated
I get error in browser
Cannot use 'in' operator to search for 'data' in undefined
{
jsonapi: {
version: "1.0",
meta: {
links: {
self: {
href: "http://jsonapi.org/format/1.0/"
}
}
}
},
"data": [
{
"type": "node--page",
"id": "string",
"attributes": {
"drupal_internal__nid": 0,
"drupal_internal__vid": 0,
"langcode": {
"value": "string",
"language": null
},
"revision_timestamp": 0,
"revision_log": "",
"status": true,
"title": "string",
"created": 0,
"changed": 0,
"promote": false,
"sticky": false,
"default_langcode": true,
"revision_default": true,
"revision_translation_affected": true,
"metatag": {},
"path": {
"alias": "string",
"pid": 0,
"langcode": "string",
"pathauto": 0
},
"body": {
"value": "string",
"format": "string",
"summary": "string"
},
"subtitle": {
"value": "string",
"format": "string"
}
},
"relationships": {
"node_type": {
"data": {
"type": "node_type--node_type",
"id": "string"
}
},
"revision_uid": {
"data": {
"type": "user--user",
"id": "string"
}
},
"uid": {
"data": {
"type": "user--user",
"id": "string"
}
},
"menu_link": {
"data": {
"type": "menu_link_content--menu_link_content",
"id": "string"
}
},
"sections": {
"data": [
{
"type": "string",
"id": "string"
}
]
}
},
"links": {
"property1": {
"href": "string",
"meta": {}
},
"property2": {
"href": "string",
"meta": {}
}
},
"meta": {}
}
],
"meta": {},
"links": {
"property1": {
"href": "string",
"meta": {}
},
"property2": {
"href": "string",
"meta": {}
}
},
"jsonapi": {
"version": "string",
"meta": {}
}
}
It wrong JSON:API format? Help me understand this mistake )
Thank you!
The jsonapi spec allows for the top-level 'links' section to contain a links object, which in turn can contain a related link. We should handle this in the related
code.
https://jsonapi.org/format/#document-resource-objects
In addition, a resource object MAY contain any of these top-level members:
<...snip...>
links: a links object containing links related to the resource.
The related
handling code should be able to handle links
both as url strings and as objects (href
and meta
), as per the spec:
I'm starting to rely on this library more heavily and I'm starting to have a need for computed properties on models. For example, a formatted price computed property on an item model.
I'm wondering if there is an easy way to integrate this with something like vuex-orm. Coming from Ember, I'm used to having this JSON:API and ORM layer working out of the box.
It seems like if I use this library to fetch data and then manually re-insert it using vuex-orm, I'll end up with two copies in the store.
It looks like they have various plugins like Vuex ORM Axios so maybe this feature should exist as a plugin over there?
An alternate idea would be for this library to provide a hook which can override the mechanism that puts data into the store. That would allow integration with vuex-orm. Not sure if this is a bad idea though.
Edit: I realized I can hook into the mutation from this library like so:
new Vuex.Store({
mutations: {
'jv/add_records'(state, records) {
console.log(state, records);
},
})
But I don't think this overrides the original mutation from this library.
One thing I miss after moving away from reststate-vuex is automatic tracking of loading state.
It would be a nice feature to add to remove some boilerplate around adding loading indicators to the UI.
There is the possibility for the action to be smarter about how it returns data. For example, it could return from the store immediately if the data is 'fresh' rather than always querying the API. This would improve performance.
This is probably best implemented by looking at cache timeout info as provided by the API, possibly some other headers like etags etc?
When an item contains relationships, how should these be handled?
2 options:
While 2 sounds nice, in reality this requires storing an empty object so that the reference exists until it is fetched. This makes it hard to distinguish between un-fetched and non-existent (deleted) objects. Removing references involves walking the whole tree, and any direct store manipulation would break things.
3 Is a bit scary, since getters could fire off asynchronous actions which in turn could modify the store, breaking the getters = synchronous read model in vuex.
1 is safe and easy to implement. We should store the rel in destructured form, so it can be passed as an arg directly to other actions.
Does this library consider singular vs plural resource names? For example, when I try to update a resource:
this.$store.dispatch('jv/patch', this.todo);
It will send a request to /api/v1/todo/24975302, however Rails has defined my endpoint as /api/v1/todos/24975302.
I noticed in your code that it might be possible to pass a string instead of a record, so I tried to specify a plural path like so:
this.$store.dispatch('jv/patch', `todos/${this.todo._jv.id}/`);
But this throws an error:
vue.runtime.esm.js?2b0e:1887 TypeError: Cannot use 'in' operator to search for '_jv' in todos/24975302/
at normToJsonapi (jsonapi-vuex.js?1c7f:380)
at Store.patch (jsonapi-vuex.js?1c7f:163)
at Array.wrappedActionHandler (vuex.esm.js?2f62:721)
at Store.dispatch (vuex.esm.js?2f62:428)
at Store.boundDispatch [as dispatch] (vuex.esm.js?2f62:322)
at VueComponent.completeTodo (DashboardTodo.vue?d0b8:37)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at HTMLButtonElement.invoker (vue.runtime.esm.js?2b0e:2178)
at HTMLButtonElement.original._wrapper (vue.runtime.esm.js?2b0e:6876)
Currently I am working around this issue using this hack:
methods: {
completeTodo() {
this.todo._jv.type = 'todos';
this.todo['is-done'] = true;
this.$store.dispatch('jv/patch', this.todo);
this.todo._jv.type = 'todo';
},
},
Inspired by #59 I've been thinking more about how we handle PATCH data.
When making a patch, it may be useful to be able to 'clean' the patch object, so that it only contains modifications.
This is useful for the workflow where a record is fetched from the API and stored, then the get
getter returns a copy, which then has a single attribute modified, and is then used in a patch
action. It makes sense for the patch to only contain the changed attribute, and not be the whole store object (this prevents accidental pushes of stale data to the store, and is more efficient).
At it's simplest, there should be a config option, which, if enabled compares attributes in the patch and the store, and keeps only those that are 'different'.
To begin with, this should only consider attributes, but longer term we may want to add further functionality:
_jv/relationships/author
from {type: 'author', id: '1'}
to {type: 'author', id: '2'}
The first part should be easy to implement, so will begin work on a PR.
There needs to be a way to pass in JSONAPI params to actions so that queries can contain filters, includes etc.
I can see 2 ways to achieve this.
Add another 'reserved' tag to the destructured data alongside _jv
- something like _jvopts
?
Make the arg to actions a (optional) list - the 2nd item of which is query params.
1 means that string args can't have options, unless they're in 'raw' jsonapi form. This could work, but makes it harder to extend this to things like getter params when filtering store lookups. It also means that the opts need to be removed from the object as it enters the store, which is more work.
2 works for both strings and data objects. It keeps data and params separate, though it requires that the arg is always an array, or needs a little bit of introspection - i.e.:
if (Array.isArray(data)) {
[ data, params] = data
}
As to the structure of params, the ideal form is an object with keys corresponding to jsonapi params (filter, include etc). Since some of these aren't strongly defined in the spec (filter and pagination) there should potentially be a param_string
key which just contains a list of params which will be verbatim added to the query string. This could even be the first implementation, with specific keys added later where it makes sense to add structure.
As suggested by @colinhiggs
Currently helper methods are only used 'internally', and are only exported as _testing
for the test suite.
Some or all of these methods are potentially useful for use outside of the module (such as data (de)normalisation, patch cleanup etc).
We should either rename _testing
to utils
, or just create a separate utils
for ease of use.
Currently followRelationships expands included object only to one level.
According to JSON:API specs, it's possible to include multiple levels of relations like this: /articles/1?include=comments.author (https://jsonapi.org/format/#fetching-includes).
I'd like to propose to make followRelationships recursive to support this. I already have some draft for this so can create PR with the code.
Would be great if this (Amazing lib!) adds Nuxt Universal SSR support.
There is no "meta" in response, if it placed in the root of the object.
JSONAPI record look like this, for example:
{
"meta": {
"totalPages": 13
},
"data": [
{
"type": "articles",
"id": "3",
"attributes": {
"title": "JSON:API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z"
}
}
]
}
I'm trying to run this with strict mode but notice the following error:
vue.runtime.esm.js?2b0e:1887 Error: [vuex] do not mutate vuex store state outside mutation handlers.
at assert (vuex.esm.js?2f62:87)
at Vue.store._vm.$watch.deep (vuex.esm.js?2f62:763)
at Watcher.run (vue.runtime.esm.js?2b0e:4529)
at Watcher.update (vue.runtime.esm.js?2b0e:4503)
at Dep.notify (vue.runtime.esm.js?2b0e:730)
at Function.del [as delete] (vue.runtime.esm.js?2b0e:1125)
at actionStatusClean (jsonapi-vuex.js?1c7f:360)
It looks like the actionStatusClean
function is doing some direct state modifications?
I have a need to look up an item by id which has a polymorphic type. For example:
this.$store.getters['jv/get']({ _jv: { type: 'card' } })[this.itemId]
But this will fail because the item types returned by my JSON API are actually credit-card
and debit-card
. As an ugly hack, I can call this function repeatedly for all the possible types until one resolves with the data.
Would it make sense to have a getter that does not require specifying a type since IDs should be unique across types in the database?
When relationships are changed on an object via a post
or patch
then the object at the 'other end' of the relationship should be updated in the store to reflect this.
This is probably best implemented alongside #88
Looks like we really cannot use a custom tag (other than _jv
) because of this early assignment:
jsonapi-vuex/src/jsonapi-vuex.js
Line 39 in 563c864
Currently get of object will fully replace existing instance in the store. This may cause previously loaded relationships being lost. Example:
dispatch: get /article?include=author - will store author and article with rel=[author]
dispatch: get /article?include=comments - will store comments and article with rel=[comments], thus article.authror is not accessible anymore. this can also happen from includes/nested includes, for example:
dispatch get /authors?include=comments
dispatch get /artcles?include=author - will also replace author instance, thus all author comments won't be resolvable through author
I'd propose to improve add_records mutation to merge relationships of existing object from the store and new object.
PS: similar issue may happen when retreiving same object with different fields from different places, which will leave only last loaded fields in the store. Worth considering merging them as well.
It would be interesting to see support of undo/redo. Perhaps it is outside of the scope of this library. Currently I am doing this to undo:
methods: {
completeTodo() {
const todo = this.todo;
todo['is-done'] = true;
this.$store.dispatch('jv/patch', todo);
this.$toasted.show('Todo complete', {
action: {
text: 'Undo',
onClick: (e, toast) => {
todo['is-done'] = false;
this.$store.dispatch('jv/patch', todo);
toast.goAway(0);
},
}
});
},
In other words, I have to manually describe the opposite of the previous PATCH request and send another PATCH. Would it be feasible to add undo functionality where the vuex mutation is rolled back and the corresponding network request is sent out automatically?
Something like..
this.$store.dispatch('jv/rollback', { steps: 1 });
We could consider converting all use of snake_case variables/function names to camelCase.
One way to do this might be to use the Prettier Custom Parser API.
Or something a bit more manual, using the codemod tool. I've tried this method but I'm struggling to come up with a regex for this that codemod accepts.
When get
ing an object from the store, there should be the option to also follow relationships and get those which are in the store appended to the returned object.
The safest way to do this is to create a new key under _jv
and nest the data there, accessing it as: obj._jv.rels.relname.id.attrs
This behaviour will be toggled with a config option follow_relationships_data
The jsonapi spec allows for objects of different type to be returned in a relationship - however this is a very? rare use case. Therefore default starting point will be to drop type in the nested rels, and we can add them in under a new key (e.g. obj._jv.rels.relname.typed.type.id.attrs
later if there is demand for it.
This code will also only work initially for relationship data
links, as these will be easy to reference to the store. Relationship links
will need to call out to the API, which is trickier to manage (do we then convert link results to data
-like objects in the store?
I get the following error when issuing a patch action:
Uncaught (in promise) TypeError: Converting circular structure to JSON
at JSON.stringify (<anonymous>)
at transformRequest (defaults.js?2444:51)
at transform (transformData.js?c401:16)
at Object.forEach (utils.js?c532:224)
at transformData (transformData.js?c401:15)
at dispatchRequest (dispatchRequest.js?5270:37)
The general problem is this area in followRelationships
:
if (is_item) {
// Store attrs directly under rel_name
data[jvtag]['rels'][rel_name] = result
} else {
// Store attrs indexed by id
data[jvtag]['rels'][rel_name][id] = result
}
Using this snippet to detect circular dependencies, I am getting the following circular dependency in my code base: CIRCULAR: obj._jv.rels.seller._jv.rels.todos.521765479._jv = obj._jv = [object Object]
. In my codebase, I have a user/seller that hasMany todos.
Conceptually, part of the problem here is that calling the getter has the side effect of modifying the data (via followRelationships). And the getter is called durning both post and patch actions.
I'm still working on steps to reproduce but the general idea is:
get
action for a record with a has_many relationship (this will put a circular dep into the store)patch
or post
action on one of the dependent records. Error occurs.From the spec:
A server MUST return a 200 OK status code if an update is successful, the client’s current attributes remain up to date, and the server responds only with top-level meta data. In this case the server MUST NOT include a representation of the updated resource(s).
Change the code to handle 200
either being a full response, or meta-only (in which case handle as for 204
, but honour preserveJSON
).
From the spec:
Identification
The values of the id and type members MUST be strings.
As highlighted in #80 there are situations in which the type
and/or id
might be mis-interpreted as url characters when constructing the target url. For this reason, they should be URL encoded for safety.
There should be a way to filter the get
getter to return a subset of a collection.
We need a way to map a passed-in argument onto a filter
or equivalent in the getter.
See #1 for ideas on param handling.
Currently it returns nothing, so undefined
Maybe it should see what is returned by the API (JSONAPI says can be 200
with data of deleted item, or 204
no data) and if data present, destructure and return that?
Hi!
Update please npm version to the latest.
I got undefined key in the store when I make an action without Id, because i receive it from the server. Maybe it would be better to get id from response and commit it to the store?
Worth doing as it avoids duplication/allows better tree shaking, but needs testing to ensure no change in expected behaviour.
https://yarnpkg.com/lang/en/docs/dependency-types/#toc-peerdependencies
If you try to use status getter with Axios the undefined
returned instead of action id
.
Thanks for your help.
Hello there,
I am following the advice given here to use your very nice module with nuxt.
I created the jsonapi-vuex.js plugin and edited the nuxt config, I get the following error:
Could not find a declaration file for module 'jsonapi-vuex'. '/var/vue/nuxt2/node_modules/jsonapi-vuex/index.js' implicitly has an 'any' type.
Try npm install @types/jsonapi-vuex
if it exists or add a new declaration (.d.ts) file containing declare module 'jsonapi-vuex';
ts(7016)
Could not find a declaration file for module 'jsonapi-vuex'. '/var/vue/nuxt2/node_modules/jsonapi-vuex/index.js' implicitly has an 'any' type.
Try npm install @types/jsonapi-vuex
if it exists or add a new declaration (.d.ts) file containing declare module 'jsonapi-vuex';
ts(7016)
I'm new to vue.js, I'm guessing I have to add your module to my config somewhere, but where?
Currently followRelationships includes related objects under _jv.rels which is not very "beatiful". Especially, if there will be multiple levels of relations:
article._jv.rels.comments._jv.rels.author
According to JSON:API specs, attributes and relations are both fields and there must not be attribute and relation with the same name (https://jsonapi.org/format/#document-resource-object-fields).
I'd like to suggest injecting related objects already at top level of the object, which should be safe, thus making access to nested objects more easy to read and understand:
article.comments.author
There seems to be an edge case where this sequence of events can happen for a patch action:
processIncludedRecords
will trigger some addRecords
mutationsdeleteRecord
mutation will delete the data that was just added by processIncludedRecords
jsonapiToNorm
overwrites the data variableaddRecords
adds a different type of record due to the overwritten data variableThe end result is that we lost the included records. Off the top of my head, we might be able to solve this by moving processIncludedRecords
after the delete/add/update mutations.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.