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

No way to do UPSERT using PUT #261

Closed
qrilka opened this issue Oct 21, 2013 · 13 comments
Closed

No way to do UPSERT using PUT #261

qrilka opened this issue Oct 21, 2013 · 13 comments

Comments

@qrilka
Copy link

qrilka commented Oct 21, 2013

According to HTTP spec it is possible to create new resource by PUTting to its desired URI - http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6 :

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.

And it's not possible with flask-restless as it requires table row to be already present:

# create a SQLAlchemy Query which has exactly the specified row
query = query_by_primary_key(self.session, self.model, instid)
if query.count() == 0:
    abort(404)
@jfinkels
Copy link
Owner

jfinkels commented Dec 2, 2013

The relevant part of the specification is as follows, with emphasis added.

If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.

So the server can allow this behavior, but it is not required. That being said, I might be able to be convinced that this is a useful feature. Is there any real-world situation in which being able to specify the primary key (for example, PUT /person/1 ... as opposed to PUT /person ...) is useful?

@qrilka
Copy link
Author

qrilka commented Dec 2, 2013

The situation was stated in issue title - to do an UPSERT. With current flask-restless API I don't see any way to do it without either running multiple REST calls (in my prototype for which I used flask-restless I just run POST and then PUT which give update after insert with the same values) or just switching to ordinary flask handlers.
BTW primary keys are not always the case - in my prototype I do host discovery and use MAC address as a primary key also it is not very rare to see UUID used for such purposes.

@jfinkels
Copy link
Owner

Hmm, this seems like it might be difficult to implement given the current code. I'm still a little confused about what you are looking for, though. Can you give me an example of an HTTP request that should perform an upsert, and describe the state of the model before and after the request?

@qrilka
Copy link
Author

qrilka commented Mar 13, 2014

Actually I have finished that prototype and dont' have such tasks at the moment.
But the example was like the following:
I was doing host discovery and used flask to store discovered machine data and MAC was used as a primary key for that table (actually MAC for IPMI interface). So using PUT on /api/host/ I wanted to idemponently UPSERT host data into the database. As it is not possible right now in flask-restless I have used 2 calls: POST + PUT

@jfinkels
Copy link
Owner

So what you want is this:

If the database is initially empty, a request

PUT /api/person/1 HTTP/1.1
Host: example.com

{"name": "Foo"}

should create a new row in the table in which field 'id' (the primary key, say) has value 1 and field 'name' has value "Foo".

Then subsequent requests

PUT /api/person/1 HTTP/1.1
Host: example.com

{"name": "Bar"}

should update the existing row of the table so that it has ID 1 but now has name "Bar"?

@qrilka
Copy link
Author

qrilka commented Mar 13, 2014

Looks like it was something like that, not sure that it's very frequent usecase but sometimes it could be useful

@davismj
Copy link

davismj commented Mar 28, 2014

A PUT typically has an upsert behavior and does NOT specify the primary key in the URI.

Should create a new instance of widget in the database:
PUT: /api/widget
Request body: { attribute: 'something' }

Should update an existing instance of widget in the database, if it exists, or create a new one if no resource was found with that primary key:
PUT: /api/widget
Request body: { id: 1, attribute: 'something else' }

@jfinkels
Copy link
Owner

jfinkels commented Apr 4, 2014

@davismj Thanks for the clarification. So in the first case, the PUT request is really acting like a POST, and in the second the PUT request is acting like a PATCH (that is, a request to PUT /api/widget with body {"id": 1, "foo": "bar"} is really like a request to PATCH /api/widget/1 with body {"foo": "bar"}), except if the ID doesn't exist, then it acts like a POST but with a specified ID?

@davismj
Copy link

davismj commented Apr 5, 2014

yes, although, put api/widget/1 acts like a post optionally, put api/widget should always act like a post

jfinkels added a commit that referenced this issue Feb 19, 2015
Before the behavior of Flask-Restless was a bit arbitrary. Now we force
it to comply with a concrete (though still changing) specification,
which can be found at http://jsonapi.org/.

This is a (severely) backwards-incompatible change, as it changes which
API endpoints are exposed and the format of requests and responses.

This fixes (or at least makes it much easier to fix or much easier to
mark as "won't fix") several issues, including but not limited to

  - #87
  - #153
  - #168
  - #193
  - #208
  - #211
  - #213
  - #243
  - #252
  - #253
  - #258
  - #261
  - #262
  - #303
  - #394
jfinkels added a commit that referenced this issue Feb 23, 2015
Previously, the behavior of Flask-Restless was a bit arbitrary. Now we
force it to comply with a concrete (though still changing)
specification, which can be found at http://jsonapi.org/.

This is a (severely) backwards-incompatible change, as it changes which
API endpoints are exposed and the format of requests and responses.

This change also moves JSON API compliance tests to a convenient
distinct test module, `tests.test_jsonapi.py`, so that compliance with
the specification can be easily verified. These tests correspond to
version 1.0rc2 of the JSON API specification, which can be found in
commit json-api/json-api@af5dfcc.

This change fixes (or at least makes it much easier to fix or much
easier to mark as "won't fix") quite a few issues, including but not
limited to

  - #87
  - #153
  - #168
  - #193
  - #208
  - #211
  - #213
  - #243
  - #252
  - #253
  - #258
  - #261
  - #262
  - #303
  - #394
jfinkels added a commit that referenced this issue Feb 24, 2015
Previously, the behavior of Flask-Restless was a bit arbitrary. Now we
force it to comply with a concrete (though still changing)
specification, which can be found at http://jsonapi.org/.

This is a (severely) backwards-incompatible change, as it changes which
API endpoints are exposed and the format of requests and responses.

This change also moves JSON API compliance tests to a convenient
distinct test module, `tests.test_jsonapi.py`, so that compliance with
the specification can be easily verified. These tests correspond to
version 1.0rc2 of the JSON API specification, which can be found in
commit json-api/json-api@af5dfcc.

This change fixes (or at least makes it much easier to fix or much
easier to mark as "won't fix") quite a few issues, including but not
limited to

  - #87
  - #153
  - #168
  - #193
  - #208
  - #211
  - #213
  - #243
  - #252
  - #253
  - #258
  - #261
  - #262
  - #303
  - #394
jfinkels added a commit that referenced this issue Mar 3, 2015
Previously, the behavior of Flask-Restless was a bit arbitrary. Now we
force it to comply with a concrete (though still changing)
specification, which can be found at http://jsonapi.org/.

This is a (severely) backwards-incompatible change, as it changes which
API endpoints are exposed and the format of requests and responses.

This change also moves JSON API compliance tests to a convenient
distinct test module, `tests.test_jsonapi.py`, so that compliance with
the specification can be easily verified. These tests correspond to
version 1.0rc2 of the JSON API specification, which can be found in
commit json-api/json-api@af5dfcc.

This change fixes (or at least makes it much easier to fix or much
easier to mark as "won't fix") quite a few issues, including but not
limited to

  - #87
  - #153
  - #168
  - #193
  - #208
  - #211
  - #213
  - #243
  - #252
  - #253
  - #258
  - #261
  - #262
  - #303
  - #394
jfinkels added a commit that referenced this issue Mar 5, 2015
Previously, the behavior of Flask-Restless was a bit arbitrary. Now we
force it to comply with a concrete (though still changing)
specification, which can be found at http://jsonapi.org/.

This is a (severely) backwards-incompatible change, as it changes which
API endpoints are exposed and the format of requests and responses.

This change also moves JSON API compliance tests to a convenient
distinct test module, `tests.test_jsonapi.py`, so that compliance with
the specification can be easily verified. These tests correspond to
version 1.0rc2 of the JSON API specification, which can be found in
commit json-api/json-api@af5dfcc.

This change fixes (or at least makes it much easier to fix or much
easier to mark as "won't fix") quite a few issues, including but not
limited to

  - #87
  - #153
  - #168
  - #193
  - #208
  - #211
  - #213
  - #243
  - #252
  - #253
  - #258
  - #261
  - #262
  - #303
  - #394
jfinkels added a commit that referenced this issue Mar 7, 2015
Previously, the behavior of Flask-Restless was a bit arbitrary. Now we
force it to comply with a concrete (though still changing)
specification, which can be found at http://jsonapi.org/.

This is a (severely) backwards-incompatible change, as it changes which
API endpoints are exposed and the format of requests and responses.

This change also moves JSON API compliance tests to a convenient
distinct test module, `tests.test_jsonapi.py`, so that compliance with
the specification can be easily verified. These tests correspond to
version 1.0rc2 of the JSON API specification, which can be found in
commit json-api/json-api@af5dfcc.

This change fixes (or at least makes it much easier to fix or much
easier to mark as "won't fix") quite a few issues, including but not
limited to

  - #87
  - #153
  - #168
  - #193
  - #208
  - #211
  - #213
  - #243
  - #252
  - #253
  - #258
  - #261
  - #262
  - #303
  - #394
jfinkels added a commit that referenced this issue Mar 8, 2015
Previously, the behavior of Flask-Restless was a bit arbitrary. Now we
force it to comply with a concrete (though still changing)
specification, which can be found at http://jsonapi.org/.

This is a (severely) backwards-incompatible change, as it changes which
API endpoints are exposed and the format of requests and responses.

This change also moves JSON API compliance tests to a convenient
distinct test module, `tests.test_jsonapi.py`, so that compliance with
the specification can be easily verified. These tests correspond to
version 1.0rc2 of the JSON API specification, which can be found in
commit json-api/json-api@af5dfcc.

This change fixes (or at least makes it much easier to fix or much
easier to mark as "won't fix") quite a few issues, including but not
limited to

  - #87
  - #153
  - #168
  - #193
  - #208
  - #211
  - #213
  - #243
  - #252
  - #253
  - #258
  - #261
  - #262
  - #303
  - #394
@jfinkels
Copy link
Owner

This is no longer relevant, since Flask-Restless now follows the JSON API specification, which only allows POST and PATCH requests.

@qrilka
Copy link
Author

qrilka commented Feb 12, 2016

@jfinkels if so, shouldn't it appear on http://jsonapi.org/implementations/ ?

@jfinkels
Copy link
Owner

Technically, the code implementing JSON API is not released yet. I'd like to release at least a beta version before submitting the project to that list.

@jfinkels
Copy link
Owner

In any case, I just created issue #489 for tracking that issue.

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

No branches or pull requests

3 participants