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

Creating new relationship #1158

Open
runk opened this Issue Apr 26, 2017 · 7 comments

Comments

Projects
None yet
6 participants
@runk

runk commented Apr 26, 2017

I think this topic was discussed several times, but I cannot find an answer to my question. I'm quite new to JSON API, so excuse me for my ignorance.

Assume there's an article resource, article has many comments.

/articles/1 - article resource.
/articles/1/comments - article's comments, related resource.

How do I create a comment? Am I right that I have to do two calls?

First,

POST /articles/1/comments
{
  data: {
    "type": "comments",
    "attributes": {
      "message": "Hello there"
    }
  }
}

Assume comment resource just created gets id 2.

.. and then link it to an article:

POST /articles/1/relationships/comments
{
  data: [
    { "type": "comments", id: 2 }
  ]
}

This is not quite making sense to me. Why do I have to create a relationship if related resource sits "under" /articles/1 namespace? It makes sense to me to do it in case with many-to-many relationship, but why it is proposed for many-to-one?

Should I include a relationship block during comment creation, that points to a parent article? But again, why would I do it if I'm working within article's namespace /articles/1/comments?

Please point me to the right place in spec.

@beauby

This comment has been minimized.

Show comment
Hide comment
@beauby

beauby Apr 26, 2017

Contributor

The spec says

A resource can be created by sending a POST request to a URL that represents a collection of resources.

Your /articles/1/comments represents a collection of resources (namely that of comments for the article with id 1). All good so far.

Now the part you may be missing is that the spec never says "the created resource MUST have exactly the same attributes and linkage data as the creation payload". Some attributes/relationships may be decided by the server (such as here, where the article id is decided, from the route, by the server).

Contributor

beauby commented Apr 26, 2017

The spec says

A resource can be created by sending a POST request to a URL that represents a collection of resources.

Your /articles/1/comments represents a collection of resources (namely that of comments for the article with id 1). All good so far.

Now the part you may be missing is that the spec never says "the created resource MUST have exactly the same attributes and linkage data as the creation payload". Some attributes/relationships may be decided by the server (such as here, where the article id is decided, from the route, by the server).

@jamesplease

This comment has been minimized.

Show comment
Hide comment
@jamesplease

jamesplease Apr 26, 2017

Contributor

How do I create a comment? Am I right that I have to do two calls?

The spec is pretty light on the behavior of the /resourceOne/:resourceOneId/resourceTwo endpoints. I only see it referenced for GET requests, so if I were to author an implementation of JSON API, I'm not sure if I'd add support for write endpoints.

The way that I perform this operation in one call is to just use the regular /comments endpoint. It's really nothing fancy, because a resource object can represent its attributes and its relationships.

POST /comments

{
  data: {
    type: 'comments'
    attributes: { ... },
    relationships: {
      article: {
        data: {
          type: 'articles'
          id: 1
        }
      }
    }
  }
}

So far I've only used endpoints of the form articles/1/comments as a handy shortcut for reading data. It doesn't seem too convenient for writing imo, given things like the ambiguity you mentioned around m-to-1 and m-to-n relationships (is it pointing to a list, or not?)

Contributor

jamesplease commented Apr 26, 2017

How do I create a comment? Am I right that I have to do two calls?

The spec is pretty light on the behavior of the /resourceOne/:resourceOneId/resourceTwo endpoints. I only see it referenced for GET requests, so if I were to author an implementation of JSON API, I'm not sure if I'd add support for write endpoints.

The way that I perform this operation in one call is to just use the regular /comments endpoint. It's really nothing fancy, because a resource object can represent its attributes and its relationships.

POST /comments

{
  data: {
    type: 'comments'
    attributes: { ... },
    relationships: {
      article: {
        data: {
          type: 'articles'
          id: 1
        }
      }
    }
  }
}

So far I've only used endpoints of the form articles/1/comments as a handy shortcut for reading data. It doesn't seem too convenient for writing imo, given things like the ambiguity you mentioned around m-to-1 and m-to-n relationships (is it pointing to a list, or not?)

@olosegres

This comment has been minimized.

Show comment
Hide comment
@olosegres

olosegres Jun 8, 2017

Contributor

Actually, when you POST to /articles/1/comments server should create relation automatically, without need to POST /articles/1/relationships/comments.

But if you POST to /comments, you should add article's relationship to the body of request.

If some comment already exist on server, you may POST /articles/1/relationships/comments with it's id to create a relationship.

Contributor

olosegres commented Jun 8, 2017

Actually, when you POST to /articles/1/comments server should create relation automatically, without need to POST /articles/1/relationships/comments.

But if you POST to /comments, you should add article's relationship to the body of request.

If some comment already exist on server, you may POST /articles/1/relationships/comments with it's id to create a relationship.

@hibaymj

This comment has been minimized.

Show comment
Hide comment
@hibaymj

hibaymj Jul 6, 2017

I see a couple things that stick out to me as odd here.

  1. The convention of /resource/{id}/{rel-name} is not mentioned anywhere as part of the spec that I can find, therefor it is a poor idea to assume the existence of a resource at that particular URL. It is fortunate it was not included in the spec, as this would have further crippled the hypermedia capabilities of json-api.

  2. I would agree with @jmeas that as defined in the spec, the back reference method of defining the relationship is best, however it is unintuitive and would require some form of mental gymnastics by the user to reason out.

A possible extension and potentially currently supported option which is less counter intuitive come to mind.

  • One solution would be to extend the specification by allowing POST or PATCH requests to the relationships link to contain a 'resource object' as well as a 'resource identifier object', following the same error handling rules as previously defined.

  • A less ideal, but I think currently supported method by the spec would be the POST or PATCH a compound document with a resource identifier object using a user defined ID to the relationships link with an included resource object.

hibaymj commented Jul 6, 2017

I see a couple things that stick out to me as odd here.

  1. The convention of /resource/{id}/{rel-name} is not mentioned anywhere as part of the spec that I can find, therefor it is a poor idea to assume the existence of a resource at that particular URL. It is fortunate it was not included in the spec, as this would have further crippled the hypermedia capabilities of json-api.

  2. I would agree with @jmeas that as defined in the spec, the back reference method of defining the relationship is best, however it is unintuitive and would require some form of mental gymnastics by the user to reason out.

A possible extension and potentially currently supported option which is less counter intuitive come to mind.

  • One solution would be to extend the specification by allowing POST or PATCH requests to the relationships link to contain a 'resource object' as well as a 'resource identifier object', following the same error handling rules as previously defined.

  • A less ideal, but I think currently supported method by the spec would be the POST or PATCH a compound document with a resource identifier object using a user defined ID to the relationships link with an included resource object.

@rintaun

This comment has been minimized.

Show comment
Hide comment
@rintaun

rintaun Sep 15, 2018

I realize this issue has been inactive for quite some time, but as I read the specification, nothing normative seems to be said regarding the structure of URLs.

For example, although URLs such as /articles/1/relationships/comments are included in a number of examples, the /relationships bit is not mentioned even once in the actual normative text of the specification.

If the URLs shown in the examples are meant to be normative, that needs to be explicitly stated; without such a statement, my personal opinion is that they must be considered non-normative. If the specification is intended to cover the structure of resource URLs, quite a significant amount of work will be necessary to make a robust specification for that structure -- personally, I believe that it should be considered beyond the scope of JSON:API.

Proceeding with the assumption that I am not wrong in my reading, most likely, any of the approaches discussed above would be acceptable under v1.0 of the specification (as well as the v1.1 draft as it exists as of this writing).

Of course, it is entirely possible that I'm wrong, and have missed something in my many readings of the spec. In that case, could someone please point me to where resource URL requirements are described?

rintaun commented Sep 15, 2018

I realize this issue has been inactive for quite some time, but as I read the specification, nothing normative seems to be said regarding the structure of URLs.

For example, although URLs such as /articles/1/relationships/comments are included in a number of examples, the /relationships bit is not mentioned even once in the actual normative text of the specification.

If the URLs shown in the examples are meant to be normative, that needs to be explicitly stated; without such a statement, my personal opinion is that they must be considered non-normative. If the specification is intended to cover the structure of resource URLs, quite a significant amount of work will be necessary to make a robust specification for that structure -- personally, I believe that it should be considered beyond the scope of JSON:API.

Proceeding with the assumption that I am not wrong in my reading, most likely, any of the approaches discussed above would be acceptable under v1.0 of the specification (as well as the v1.1 draft as it exists as of this writing).

Of course, it is entirely possible that I'm wrong, and have missed something in my many readings of the spec. In that case, could someone please point me to where resource URL requirements are described?

@jamesplease

This comment has been minimized.

Show comment
Hide comment
@jamesplease
Contributor

jamesplease commented Sep 15, 2018

@rintaun

This comment has been minimized.

Show comment
Hide comment
@rintaun

rintaun Sep 15, 2018

@jamesplease Thank you :) I suppose that's what happens what you hyperfocus on one thing... I had completely skipped over the recommendations page.

rintaun commented Sep 15, 2018

@jamesplease Thank you :) I suppose that's what happens what you hyperfocus on one thing... I had completely skipped over the recommendations page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment