Follow-up from #1816354: Add a REST module, starting with DELETE: The REST module should allow PUT requests to update entities. The request Content-Type format will be hard-coded to JSON-LD for now, everything else will be rejected.

IMO it would be cool to allow partial updates, too. So instead of PUTing the whole resource representation to the endpoint it should be possible to just PUT the title property of a node for example. Strictly speaking this would be the semantics of HTTP PATCH. Clients do not have to retrieve the resource representation beforehand, parse it and replace parts. They can just PUT the parts they are interested in.

Work is done in the PUT-update-1839366 branch in the REST sandbox.

Comments

webchick’s picture

Component: base system » rest.module
Priority: Normal » Major

This seems pretty important to having web services in core.

klausi’s picture

Issue summary: View changes

added issue dependencies.

klausi’s picture

Status: Active » Needs review
StatusFileSize
new6.65 KB
new33.27 KB

First patch that adds a put() method and simpletests.

Interdiff is against the issues mentioned in the summary, please review that.

klausi’s picture

Issue summary: View changes

typo

moshe weitzman’s picture

Looks pretty straightforward to me. Hopefully we can sort the dependencies quickly.

moshe weitzman’s picture

Issue summary: View changes

added link to sandbox

klausi’s picture

StatusFileSize
new18.36 KB

Simple reroll, after #1834288: RESTfully request an entity with JSON-LD serialized response got committed, still depends on #1839346: REST module: POST/create. No other changes.

klausi’s picture

StatusFileSize
new3.08 KB
new20.31 KB

Updated patch, now that deserialization basically works.

The question is now how this operation should work on the entity API level. A PUT request has to completely replace the existing entity. Currently with this patch properties that are omitted do not get removed as they should. We also need test cases for this, which we currently do not have.

Partial updates are now discussed in #1826688: REST module: PATCH/update.

klausi’s picture

StatusFileSize
new4.73 KB

Simple reroll after #1839346: REST module: POST/create got committed.

klausi’s picture

Issue summary: View changes

removed GET patch dependency.

Status: Needs review » Needs work
Issue tags: -WSCCI

The last submitted patch, rest-put-1839366-6.patch, failed testing.

klausi’s picture

Status: Needs work » Needs review
Issue tags: +WSCCI

#6: rest-put-1839366-6.patch queued for re-testing.

moshe weitzman’s picture

The question is now how this operation should work on the entity API level. A PUT request has to completely replace the existing entity. Currently with this patch properties that are omitted do not get removed as they should. We also need test cases for this, which we currently do not have.

Sounds to me like we should do an entity_create() and pass in all the stuff that came from the incoming PUT. We should make sure that entity->id is set. Then, call entity->save. At no point did we call entity_load(). Sound good?

klausi’s picture

StatusFileSize
new5.28 KB
new7.05 KB

To answer myself: the current implementation already replaces the entity as expected, so there is nothing we need to change here. Yay!

I implemented a test case that demonstrates that omitted entity properties are deleted. So I guess this i pretty ready.

Status: Needs review » Needs work
Issue tags: -WSCCI

The last submitted patch, rest-put-1839366-10.patch, failed testing.

klausi’s picture

Status: Needs work » Needs review
Issue tags: +WSCCI

#10: rest-put-1839366-10.patch queued for re-testing.

damien tournoud’s picture

Status: Needs review » Needs work

"A PUT request has to completely replace the existing entity. Currently with this patch properties that are omitted do not get removed as they should."

This feels debatable. HTTP/1.1 just says that:

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.

The intention of the client is to modify an existing resource with a new representation of this resource. The new representation only supersedes the representation that the client would retrieve in a GET method.

As a consequence, only the fields that would be present in the representation that would be generated for that particular client (in a GET request) should be taken into account. Fields that the client doesn't have access to should remain completely unaffected.

moshe weitzman’s picture

Status: Needs work » Reviewed & tested by the community

@Damien - the existing rest services don't care about access controlled fields either (CREATE, READ, ...). I agree that this is non-ideal and that we need to discuss it in its own issue. I've opened #1866908: Honor entity and field access control in REST Services. In the meanwhile, when you grant a role the rest permissions, you are granting full access to entity fields.

This is ready.

damien tournoud’s picture

Status: Reviewed & tested by the community » Needs work

Sorry, but this is not ready. The current approach cannot flight. We cannot just throw away the old entity completely, as it can contain technical information that should not be touched (created date, etc.).

damien tournoud’s picture

PUT has never been intended to be the equivalent of DELETE + PUT. In our case, the proper algorithm for PUT needs to be:

  • Load the original entity, if it doesn't exist, throw a 404 (because we don't intend to support creating entities with PUT for now);
  • Check that the original entity matches any conditional headers (If-Match / If-None-Match / If-Modified-Since) of the PUT request; if not, throw a 409 Conflict; (this cannot be implemented for now, because we still don't have proper ETag for entities);
  • Validate that the replacement entity is valid, if not throw a 400 or 403;
  • Merge the replacement entity with the old entity;
  • Call save; on success, return 204; on error throw a 400 or a 500 depending on the error.
klausi’s picture

Status: Needs work » Needs review
StatusFileSize
new3.06 KB
new7.68 KB

Note: the current code never issues the deletion of an entity (no delete hooks are fired for example). It is simply completely replaced.

New patch:
* Added the 404 logic on entities that don't exist yet, added a test case for that.
* Changed success status code to 204.

Since we do not take entity access control into account in this patch merging or replacing the entity is equivalent, no need to change the code. Entity validation is also a followup issue, since that functionality is still in the works.

mitchell’s picture

Check that the original entity matches any conditional headers (If-Match / If-None-Match / If-Modified-Since) of the PUT request; if not, throw a 409 Conflict; (this cannot be implemented for now, because we still don't have proper ETag for entities);

#1869338: Support ETag + If-Match for PATCH requests to prevent concurrent updates

klausi’s picture

StatusFileSize
new5.6 KB

Rerolled after #1826688: REST module: PATCH/update was committed. No other changes.

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

Good to go. We'll tackle entity validation in #1696648: [META] Untie content entity validation from form validation

dries’s picture

Status: Reviewed & tested by the community » Fixed

Committed to 8.x. Thanks.

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

removed committed dependency.