GithubHelp home page GithubHelp logo

mrichar1 / jsonapi-vuex Goto Github PK

View Code? Open in Web Editor NEW
155.0 6.0 23.0 3.58 MB

Use a JSONAPI api with a Vuex store, with data restructuring/normalization.

License: GNU Affero General Public License v3.0

JavaScript 100.00%
jsonapi vue vuejs2 vuex normalize rest

jsonapi-vuex's People

Contributors

daryledesilva avatar dependabot[bot] avatar elthariel avatar mrichar1 avatar staaam avatar stefanvanherwijnen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

jsonapi-vuex's Issues

Processing included for post/patch/delete

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.

"RangeError: Maximum call stack size exceeded" when using `followRelationshipsData`

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'
            }
          }
        ])
JSON response from server
{
  "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?

TypeError: Converting circular structure to JSON

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"
        }
    ]
}

Getter for relationships?

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.

Server-side search results

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.

PATCH issue with links

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.

RangeError: Maximum call stack size exceeded

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.

Unable to resubmit with data returned from action

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?

followRelationships method doesn't properly maps relations

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

Config handling

Add support for config options, overriding defaults when passed in when instantiating module.

Follow included data

We should look at the included tag and add any included objects to the store.

Dispatch API without array args

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?

Should Throw Error for 4xx, 5xx etc

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.

WARN Cannot stringify a function isRel and getRelated error

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

this returned from jv
{
  "_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

I use this JSON format
{
  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!

top-level 'related' links

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.

Integration with vuex-orm?

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.

Cached returns from actions (via getters)

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?

Fetching related items

When an item contains relationships, how should these be handled?

2 options:

  1. Store the type and id (as-is) and expect the user to pull them as needed.
  2. Store a reference to the other objects in the store.
  3. Store a promise to fetch the object.

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.

Plural Resource Names

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';
  },
},

Clean up patch object to only contain modifications

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:

  1. look at changes to relationship links (e.g. modifying _jv/relationships/author from {type: 'author', id: '1'} to {type: 'author', id: '2'}
  2. look at changes to relationship data (where 'followed' relationship data in the the root is modified, generate a 2nd patch targeted against the related object's URL).

The first part should be easy to implement, so will begin work on a PR.

Filtering etc on API queries

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.

  1. Add another 'reserved' tag to the destructured data alongside _jv - something like _jvopts?

  2. 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.

Export helper methods

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.

[NFR] Nuxt support

Would be great if this (Amazing lib!) adds Nuxt Universal SSR support.

"meta" is not recording

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"
      }
    }
  ]
}

Webpack Parse Fail in 0.0.16

Got everything set up today, just as in the docs, and when Webpack compiles I'm getting the following error:

image

I'm using:

  • Vue 2.6.6
  • Vuex 3.0.1
  • jsonapi-vuex 0.0.16

Pretty sure I'm set up properly, so hoping to get some advice. Thanks.

image

Error: [vuex] do not mutate vuex store state outside mutation handlers

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?

Getter with polymorphic type

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?

Multiple loads of same object with different includes should merge relationships

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.

Support Undo

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 });

Follow relationships from the store

When geting 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?

Bug: followRelationships introducing cyclic dependency

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:

  • Call the get action for a record with a has_many relationship (this will put a circular dep into the store)
  • Call the patch or post action on one of the dependent records. Error occurs.

Handle PATCH with 200 and meta-only response

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).

url encoding of type and id

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.

Filtering on 'get' getter

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.

What should the delete action return?

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?

Using with nuxt

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?

followRelationships to include related object at top level instead of _jv.rels

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

processIncludedRecords for patch action happening too soon

There seems to be an edge case where this sequence of events can happen for a patch action:

  • PATCH request fires, comes back with 200 code and some included records
  • processIncludedRecords will trigger some addRecords mutations
  • deleteRecord mutation will delete the data that was just added by processIncludedRecords
  • jsonapiToNorm overwrites the data variable
  • addRecords adds a different type of record due to the overwritten data variable

The 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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.