PATCH in REST and null - rest

We have an article resource with properties:
title
image
description
status: published | draft
if we want only to remove image we make request
{title: null, image: null, description: null, status: null}
if we want only to update status we make request
{title: null, image: null, description: null, status: draft}
but in this case image also will be removed
How in REST to update only one property?

Performing partial modifications to a resource
The PATCH method can be used to perform partial modifications to a resource. The request payload should contain a set of instructions describing how the resource will be modified. See the following quote from the RFC 5789:
2. The PATCH Method
The PATCH method requests that a set of changes described in the request entity be applied to the resource identified by the Request-URI. [...]
The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version. [...]
To describe such set of instructions, you can use JSON Patch defined in the RFC 6902:
1. Introduction
JSON Patch is a format (identified by the media type application/json-patch+json) for expressing a sequence of operations to apply to a target JSON document; it is suitable for use with the HTTP PATCH method.
This format is also potentially useful in other cases in which it is necessary to make partial updates to a JSON document or to a data structure that has similar constraints [...]
Examples with JSON Patch
To update the status, you can do the following:
PATCH /articles/1 HTTP/1.1
Host: example.com
Content-Type: application/json-patch+json
[
{ "op": "replace", "path": "/status", "value": "draft" }
]
Use the following to remove the image:
PATCH /articles/1 HTTP/1.1
Host: example.com
Content-Type: application/json-patch+json
[
{ "op": "remove", "path": "/image" }
]
And use the following to update the status and remove the image:
PATCH /articles/1 HTTP/1.1
Host: example.com
Content-Type: application/json-patch+json
[
{ "op": "replace", "path": "/status", "value": "draft" },
{ "op": "remove", "path": "/image" }
]
Alternatively to JSON Patch, you may want to consider JSON Merge Patch defined in the RFC 7396: it's also a means of describing a set of modifications to a target resource's content.

Let me give an example which troubles me when using JSON-Patch message in PATCH message in a RESTFul API.
If we have a structure like:
{"books": [
{"title": "HTTP-Protocol", "image": "http.jpg", "description": "A standard book on HTTP", "status": "Available"},
{"title": "JSON-Patch", "image": "patching.jpg", "description": "Explanation on how to use json-patch in RESTFul", "status": "Planned"},
{"title": "RESTFul", "image": "fielding.jpg", "description": "Representational state transfer", "status": "Available"}
]}
Now the client who requested this information wants to change the status of the third book (RESTFul) from "Available" to "Borrowed".
Using JSON-Patch he would send the following message:
[
{
"op": "replace",
"path": "/books/2/status",
"value": "Borrowed"
}
]
Meaning that from the list, as he saw it, he wants to change the status of the third item. But since a RESTFul API call is stateless the server does not know anymore what list it gave to the client. Maybe in the mean time a new book was added and the list on the server change to:
{"books": [
{"title": "HTTP-Protocol", "image": "http.jpg", "description": "A standard book on HTTP", "status": "Available"},
{"title": "In between", "image": "destroy.jpg", "description": "Not RESTFul?", "status": "Available"},
{"title": "JSON-Patch", "image": "patching.jpg", "description": "Explanation on how to use json-patch in RESTFul", "status": "Planned"},
{"title": "RESTFul", "image": "fielding.jpg", "description": "Representational state transfer", "status": "Available"}
]}
Then this json-patch message received from the client will change the book with the title "JSON-Patch" and not the book with title "RESTFul" as intended by the client.
What is in your opinion the solution for this problem?

Related

REST API - Create resource and nested resource best practices

I have a question about REST API, especially about resource creation (and nested resources).
Suppose we have the following "GET" routes:
GET /recipes/1
{
"id": 1,
"name": "Crepes",
"ingredients": [
{"id": 1, "name": "Flour", "quantity": 100},
{"id": 2, "name": "Milk", "quantity": 15},
...
]
}
GET /recipes/1/ingredients/1
{
"name": "Flour",
"quantity": 100,
"details": "...",
...
}
My question is: what is the best practice/design for POST /recipes? (Suppose we want to create the previous recipe)
we make only 1 call:
POST /recipes
body = {
"name": "Crepes",
"ingredients": [
{"name": "Flour", "quantity": 100, ...},
{"name": "Milk", "quantity": 15, ...}
...
]
}
==> Recipe and ingredients are created at the same time
we make 1 call for recipe, and X for ingredients:
POST /recipes
body = {
"name": "Crepes"
}
POST /recipes/1/ingredients
body = {
"name": "Flour",
"quantity": 100,
...
}
...
==> recipe and ingredients are created one after the other
So, what is the best practice/design for resources and nested-resources?
Thanks !
TL; DR -- yes, you want to send a single request to the server, and permit the server to "create" as many resources as it needs to support future work.
The potentially complicating issue in HTTP is caching. One of the important ideas in REST is that it "allows references to be made to a concept before any realization of that concept exists".
Within the context of the web, that means that a client can potentially GET /recipes/1/ingredients/1 before that resource has a representation. When the server responds with 404 Not Found, that response is cacheable.
Here's an important idea: cache-invalidation has very precise semantics; a successful POST /recipes request will invalidate any locally cached copies of the /recipes resource, but it will have no effect on cached copies of /recipes/1 or /recipes/1/ingredients/1.
Which means that if you put a general purpose reverse proxy in front of your API, the copies of the different resources at the proxy won't all update together. Because the different resources aren't invalidating, there are various scenarios in which consumers of multiple resources will see inconsistent information.
The good news is that you, the origin server, control not only the representations of the resources but also the caching meta data. So you can tune the caching strategy to the best compromise among the conflicting design pressures.
In practice, you will probably find that bulk create of resources isn't a problem, because there's little reason for a client to fetch a resource before it has been created. Bulk updates are more problematic.

Should the resource ID be put in URL of PUT and PATCH requests?

Should PUT's and PATCH's URL contains ID or could it be put inside the body?
PUT /person/UUID {"name": "Jimmy"}
OR
PUT /person/{"UUID":1, "name": "Jimmy"}
( the same for the PATCH)
?
As PUT is defined as Replace the current document found at the URI location with the one provided in the payload sending a PUT request to /person should probably lead to a removal of any person managed by that particular endpoint, in case that URI represents a collection of persons.
As mentioned in this post one might use a URI without some special entity identifier in case this is an all purpose container. Think of a clipboard where you can copy some data to to later on retrieve it to paste it somewhere else. In such a case the identifier is implicitly given by the URI itself, as after all URI stands for unique resource identifier
Note that a URI as a whole identifies a resource and does not necessarily imply some form of parent-child structure. A client especially should not attempt to extract knowledge from an URI at all.
In regards to PATCH it depends. Usually one should use a media-type that is intended for patching such as JSON Patch or JSON Merge Patch.
The former representation defines certain fields that state that a field should be added, removed or replaced with a given value in a notation like the one listed below:
PATCH /my/data HTTP/1.1
Host: example.org
Content-Length: 326
Content-Type: application/json-patch+json
If-Match: "abc123"
[
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]
JSON Merge Patch however works differently. It defines some default rules that instruct a server on how to apply the changes to the target document. A document like below i.e. will either add or update field a to have value z afterwards while the property f of c's object has to be deleted. All the other remaining properties of that resource remain as they are.
PATCH /target HTTP/1.1
Host: example.org
Content-Type: application/merge-patch+json
{
"a":"z",
"c": {
"f": null
}
}
Both of these media-types could be used to send a request directly to the "collection"-resource as both can target sub-elements by definition. However, in terms of caching I'd try to avoid it.
Caching in HTTP works de facto on the URI of the resource. Any unsafe operation performed on that URI leads to the cache invalidating a stored representation for that target. I.e. if you previously invoked GET /person/1 and now perform a PUT or PATCH, which both are unsafe operations, on /person the data might get updated, though a client requesting GET /person/1 afterwards may still retrieve the cached response via the cache as it is unaware of any changes done to that resource.

What's the RESTful way to return metadata on a collection of resources?

Say I have a REST API for accessing user notifications. I have an endpoint for getting all notifications:
GET https://server:443/api/notifications
Which returns the following response:
[
{
"status": "unread",
"_id": "5db8228d710ab4b1e33f19b2",
"title": "Some title",
"time": "2019-10-29T11:29:17.402Z",
"details": "Some details...",
"user": "user1"
},
{
"status": "unread",
"_id": "5db8228d710ab4b1e33f19b3",
"title": "Some title",
"time": "2019-10-29T11:29:17.411Z",
"details": "Some other details",
"user": "user2"
},
]
Now, I'd like to also be able to retrieve the amount of notifications for each user in a single request, for which the response will be something like:
[
{
"user": "user1",
"count": 1
},
{
"user": "user2",
"count": 1
},
]
What would be the best way, in terms of REST conventions, to do that?
What would be the best way, in terms of REST conventions, to do that?
REST really doesn't answer that. REST tells you that you have resources, but it doesn't actually offer any opinion on where the "boundaries" of your resources should be.
Again, think "web pages". You could add your summary to the web page that describes notifications, and that would be fine. Or you could decide that the notifications are described on one web page, and the summary on a different web page, and that would be fine.
What REST does tell you is that caching is important; so if you think the cache controls for summary data should be different from notification data, then you want to be thinking about separating that data into a different resource. If you think the summary data and the notification data needs to be synchronized, then its more likely that they belong as part of the same resource.
Of course, there's nothing in REST that says you can't have multiple resources that return the "same" data.
If you wanted the summary to be part of the notifications resource, and also wanted that information to be independently identifiable, then you would use a fragment to describe the summary "sub-resource"; perhaps https://server:443/api/notifications#summary.

API examples using JSON PATCH for partial updates

I'm looking for the best solution to apply a partial update to an object with a REST API (ASP.NET)
I originally wanted to use "JSON Merge Patch" format (rfc7396), but I was not able to do it with ASP.NET (hard to differentiate ignored fields, and fields set to null)
I tried to use PATCH with JSON PATCH format and it is working.
Ex. :
[
{ "op": "replace", "path": "/Name", "value": "patchedValue" },
{ "op": "replace", "path": "/EnumTest", "value": "blo" },
{ "op": "replace", "path": "/SubItem/Name", "value": "patchedValue" }
]
I see that Microsoft support this format (asp.net core json patch), but I have no idea if this format is often used. I don't want to be the only one using it... I'm looking for API from big companies that is using this format for partial update. Do you have some examples ?

Can someone explain, what does the webhook do in api.ai?

I am new to api.ai. I want to send data to the web server and receive it and then give it to the users? From the documentation that I read, I understood that I have to use a webhook. But I am not sure how will api.ai send and receive the data?
Can the webhook be developed in any language?
The webhook is a web service that you implement in any language and on any platform, with an HTTP (must be https for ghome) and JSON interface, that fullfils (in their lingo) a user intent.
API.AI matches a user utterance to an intent (which then suggests entity values and a response) and they pass these in the call to your web service. You do whatever processing you need - your domain logic - and then return a speech response for the user and optionally some API.AI contexts.
You can read more about it (and about slot filling fulfillment which is a little different) here.
You can visualize the working of a webhook like a block where data request comes in JSON format somewhat like this:
{
"id": "7aef9329-4a32-4d59-b661-8bf380a0f35b",
"timestamp": "2017-06-07T05:36:12.641Z",
"lang": "en",
"result": {
"source": "agent",
"resolvedQuery": "hi",
"action": "order.pizza",
"actionIncomplete": true,
"parameters": {
"address": "",
"crust": "",
"sauce": "",
"size": "",
"time": "",
"topping": "",
"type": ""
}
}
}
and another json file is returned to it according to the prescribed settings.