Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PATCH issue with links #59

Closed
nickgronow opened this issue May 11, 2019 · 5 comments
Closed

PATCH issue with links #59

nickgronow opened this issue May 11, 2019 · 5 comments

Comments

@nickgronow
Copy link

nickgronow commented May 11, 2019

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.

@nickgronow
Copy link
Author

As a side note, really loving the work you guys have been doing with this Vuex package @mrichar1.

@mrichar1
Copy link
Owner

mrichar1 commented May 13, 2019

Thanks for raising this issue.

I've revisited the spec, and it says the following for patch:

Updating Resources
A resource can be updated by sending a PATCH request to the URL that represents the resource.
The URL for a resource can be obtained in the self link of the resource object. Alternatively, when a GET request returns a single resource object as primary data, the same request URL can be used for updates.
The PATCH request MUST include a single resource object as primary data.

Resource objects
a resource object MAY contain any of these top-level members:

  • attributes: an attributes object representing some of the resource’s data.
  • relationships: a relationships object describing relationships between the resource and other JSON:API resources.
  • links: a links object containing links related to the resource.
  • meta: a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.

So the use of links is both allowed, and actually has a specific purpose (in providing the patch URL via the self link).

I've looked at jsonapi-resources project and they have an issue open which, while not exactly the same, seems to be the equivalent issue, albeit for meta rather than links: cerebris/jsonapi-resources#1040

In the short term the workaround is to drop the links, meta, relationships etc from _jv in the normalised data before using it in the patch action, i.e something like:

['links', 'meta', 'relationships'].forEach(e => delete data['_jv'][e])

If there's a general need then I could potentially put in a helper function to make modifying the normalised data easier for patching, but otherwise it's easiest for the developer to just modify the data as they know best what they do and don't want in the patch. (It's generally always a god idea to have an mostly empty patch with onlt the changed attributes in it anyway, to avoid issues where a locally cached value overwrites a later-updated one on the server).

@nickgronow
Copy link
Author

Thanks a lot Matthew for the thorough explanation here on how to proceed. Your snippet here is excellent. Where would you recommend I do this in the code base? I should probably just continue to maintain my own fork for now then correct?

@mrichar1
Copy link
Owner

I'd always prefer to accept changes into the main project - forks are useful, but if I can support your needs here, so much the better!

If the simple snippet above is enough, then you could run it either at the point you return data from the get action (if you never use the extra data in _jv), e.g.:

this.$store.dispatch("get", "/foo/1")
  .then((data) => {
    ['links', 'meta', 'relationships'].forEach(e => delete data['_jv'][e])
    return data
  })

Alternatively, you can modify the data just before calling patch, i.e:

['links', 'meta', 'relationships'].forEach(e => delete data['_jv'][e])
this.$store.dispatch("patch", data)

In terms of helper methods, I can think of a couple of different ways of doing it. The first is to make a method that does the forEach snippet above for a given data object, i.e.:

const normPatch = (data) => {
  ['links', 'meta', 'relationships'].forEach(e => delete data['_jv'][e])
  return data

The second is to make a method, equivalent to the get getter that takes a list of desired fields and _jv keys, and returns a 'filtered' object from the store - something more like:

const getPatch = (data, fields, jvKeys) => {
  // pseudo-code
  let result = this.$store.getters['jv/get'](data)
  newData = { jvtag: {} }
  // Only add requested _jv keys
  jvKeys.forEach(e => newData['_jv'][data[e]])
  // Only add requested fields
  fields.forEach(e => newData[data[e]])
  return newData
}

I don't know if either of these approaches is useful or viable, but it's the kind of thing that could be added to the project, rather than forcing you to maintain a fork for this kind of behaviour.

@mrichar1 mrichar1 reopened this May 13, 2019
@nickgronow
Copy link
Author

Thanks for all these options Matthew. I went with your third suggestion to build a helper method for this:

    patch (item) {
      // We need to drop links for now
      const copy = Object.assign({}, item);
      ['links', 'meta'].forEach(e => delete copy['_jv'][e])
      this.$store.dispatch('jv/patch', copy)
    },

Your feedback and suggestions are tremendously appreciated man. Thanks for being so responsive to a new Vue developer who is still very green in this space.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants