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

Support for "create or update" and/or "find or create" logic with the atomic extension #1628

Open
PeterLanglois opened this issue Jun 8, 2022 · 2 comments
Labels
extension Related to existing and proposed extensions as well as extensions in general

Comments

@PeterLanglois
Copy link

When dealing with related/dependent resources, I think it would be useful to "create or update" and/or "find or create" certain records.

Say for example you have some type of post resource that can have tag resources associated with it.
If I know that all the tags in the request exist, I can do this
POST /api/posts

{
  "data": {
    "type": "post",
    "attributes": {
      "title": "foo",
      "body": "bar"
    },
    "relationships": {
      "tags": {
        "data": [
          { "id": "tech", "type": "tag" },
          { "id": "api", "type": "tag" }
        ]
      }
    }
  }  
}

If I know that all the tags are new, I can do this

{
  "atomic:operations": [
    {
      "op": "add",
      "data": {
        "type": "tag",
        "lid": "tech",
        "attributes": {
          "text": "tech"
        }
      }
    },
    {
      "op": "add",
      "data": {
        "type": "tag",
        "lid": "api",
        "attributes": {
          "text": "api"
        }
      }
    },
    {
      "op": "add",
      "data": {
        "type": "post",
        "lid": "new-post-1",
        "attributes": {
          "title": "foo",
          "body": "bar"
        },
        "relationships": {
          "tags": {
            "data": [
              { "lid": "tech", "type": "tag" },
              { "lid": "api", "type": "tag" }
            ]
          }
        }
      }
    }
  ]
}

But if I don't know about the existence of these tags prior the creation of the post, I would need to first do a GET and attempt to fetch these tags. However, since there's pretty logical/predictable defaults for this tag resource, it doesn't seem like this GET should be necessary.

My thought would be to add find_or_create and create_or_update operations and add a find_by member.

{
  "op": "find_or_create",
  "find_by": ["text"],
  "data": {
    "lid": "tech",
    "type": "tag",
    "attributes": { "text": "tech" } 
  }
}

find_by would accept an array of attributes that define a composite key and use the values specified in attributes to make that query. before attempting to create the record.
May also be reasonable to also accept lid instead of an array of attributes and attempt to match an existing resource id to the specified lid

{
  "op": "find_or_create",
  "find_by": "lid",
  "data": {
    "lid": "tech",
    "type": "tag",
    "attributes": { "text": "tech" } 
  }: 
}
@jelhan jelhan added the extension Related to existing and proposed extensions as well as extensions in general label Jun 11, 2022
@jelhan
Copy link
Contributor

jelhan commented Jun 11, 2022

Thanks for that proposal. Looks reasonable to me.

Do I assume correctly that it would be an optional feature? Meaning that a server could decide to support Atomics Operations extension but not implement find_or_create and update_or_create?

Wondering if it would be more flexible if find_by accepts a JSON:API document. I see that attributes specified for creation would often habe the same value as attributes specified for find_by. But there might be edge cases, in which you would like to find by another attribute value. Or by a relationship.

I guess it would be up to server-side implementation how values are compared? Mainly thinking about case-sensitivity.

@PeterLanglois
Copy link
Author

Meaning that a server could decide to support Atomics Operations extension but not implement find_or_create and update_or_create?

Seems reasonable to me

Wondering if it would be more flexible if find_by accepts a JSON:API document... Mainly thinking about case-sensitivity.

I'd have to think about this use case more I suppose. Generally this type of query is intended to identify some alternate or composite key. So if a resource needed to consider case-sensitivity, then "name": "foo" and "name": "FOO" should point to different resources.
This does however provide a means to query by a relationship, which I did not account for in my proposal.

Speaking of things I didn't account for initially, there should be some defined behaviour for the server when the query does not identify an alternate or composite key. As in, multiple resources were returned from that query.
It would likely either need to error or just take the first resource from the result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension Related to existing and proposed extensions as well as extensions in general
Projects
None yet
Development

No branches or pull requests

2 participants