The HATEOAS definition say that each response must contains the associated links, but following the REST pattern an URI must be the same for all operations, what changes is the HTTP method.
Per example:
Request: GET http://example.com/book
Response:
[
{
"id": 1,
"title:" "foo",
"links": {
"self": http://example.com/book/1
}
}
]
The response inform that the link that can be used to read the book data is "http://example.com/book/1", but with only this link i unknown if the user that did this request is authorized to do a DELETE or PUT for this resource.
The HATEOAS or other specification define some pattern for inform what methods are available for each resource?
Per example:
Request: GET http://example.com/book
Response:
[
{
"id": 1,
"title:" "foo",
"links": {
"self": {
"url": "http://example.com/book/1",
"methods": [
"GET",
"PUT",
"DELETE"
]
}
}
]
You should look for Siren (http://hyperschema.org/mediatypes/siren)
It will tell your clients what methods do they can use with links.
Related
I am trying to design a rest api and i have a resource with links to another resource. say
GET /resource1/id1
{
"property1": "value1",
...
"links" : [
{
"rel": "res1to2rel",
"href": "/resource2/r2"
}
]
now on a post to create resource1, i want to pass a relationship to resource2. should the POST call look like
POST /resource1
{
"res1to2rel": "/resource/r2"
}
or should it look like
POST /resource1
{
"links" : [
{
"rel": "res1to2rel",
"href": "/resource2/r2"
}
]
}
What is the best practice, should the POST match the GET or can it have properties that you dont see on GET?
There're few absolute rules when it comes to REST design, but I think that it'd be easier for the client if a resource has a consistent set of representations. When you POST a representation, you typically create a new resource. This can be made even more explicit by:
Returning 201 Created.
Returning a Location header in the response.
Returning a copy of the representation as the server sees it.
Thus, a POST might look like this:
POST /resource1 HTTP/1.1
Content-Type: application/json
{
"property1": "value1",
...
"links" : [
{
"rel": "res1to2rel",
"href": "/resource2/r2"
}
]
}
The response might then be:
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Location: /resource1/id1
{
"property1": "value1",
...
"links" : [
{
"rel": "self",
"href": "/resource1/id1"
},
{
"rel": "res1to2rel",
"href": "/resource2/r2"
}
]
}
Notice that the server is allowed to enrich the resource, in the above example by adding a "self" link.
If a client later makes a GET request against the address supplied in that LOCATION header, it'll receive the same response as the echo it received from the POST request:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"property1": "value1",
...
"links" : [
{
"rel": "self",
"href": "/resource1/id1"
},
{
"rel": "res1to2rel",
"href": "/resource2/r2"
}
]
}
This makes it easier for clients to interact with the API because it can use the same internal model for reading and writing (i.e. serialising and deserialising) representations of a resource.
I need to fetch information related to eventId from office 365 for multiple events.
Is there a way I can get that info in a single REST call?
I want specific events only (based on eventId's only)
A batch request may be what you are looking for.
See json Batching Documentation for more information
Keep in mind that batching is currently limited to 20 requests per message (known issues)
Example:
You will need to send a POST Message to the batch endpoint
https://graph.microsoft.com/v1.0/$batch
inside the body you will need to include your requests:
Note: do not include the server url (https://graph.microsoft.com/v1.0/) in the url property or the request will fail with "BadRequest - Invalid request Uri".
Request-Body:
{
"requests": [
{
"id": "1",
"method": "GET",
"url": "/me/calendarview?startdatetime=2018-03-01T18:31:34.206Z&enddatetime=2018-03-12T18:31:34.206Z"
},
{
"id": "2",
"method": "GET",
"url": "/me/events/{someEventId}"
},
]
}
When the server has processed all requests an response array containing the results will be sent back:
Server-Response:
{
"responses": [
{
"id": "2",
"status": 200,
"headers": {
"OData-Version": "4.0",
"Content-Type": "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8",
"ETag": "W/\"Z+ICSvkiAfZX7XWQAZ6IH==\""
},
"body": {
// the event object
}
},
{
"id": "1",
"status": 200,
"headers": {
"OData-Version": "4.0",
"Content-Type": "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
},
"body": {
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('aUserID')/calendarView",
"value": [
// list of found event-objects
]
}
}
]
}
Let's assume we have the following REST resource collection endpoint:
/products
The resource looks like this:
GET /products/123
Accept: application/json
{
"id": "123",
"name": "Shampoo",
...
"ingredients": [
"Sodium Lauryl Sulfate",
"Sodium Laureth Sulfate",
"Hydrochloric Acid",
...
]
}
Now, let's say I want to update the resource, and add or remove an ingredient to / from the ingredients field.
One way is to GET the resource, manipulate the array, and PUT or PATCH back. However, this is pretty chatty protocol, and it also poses scaleability problem, if the array is too big.
What is the best way to achieve this add / remove operation without having the source array?
I already explored the following: JSON Patch Specification
But it seems the spec is not REST. It uses the same resource with different "operation" like representation, which is entirely different from the resource's representation.
I would like to keep as much as possible the same representation of resource for PUT / PATCH method as it is appearing in GET.
Here are my thoughts on the matter.
Change the string type item to object
Add meta field to the object called $op
So in this design, here is how the resource looks like on GET
GET /products/123
Accept: application/json
{
"id": "123",
"name": "Shampoo",
...
"ingredients": [
{
"name": "Sodium Lauryl Sulfate"
},
{
"name": "Sodium Laureth Sulfate"
},
{
"name": "Hydrochloric Acid"
},
...
]
}
And now if I want to remove an item from the ingredients array:
PATCH /products/123
Content-Type: application/json
Accept: application/json
{
"ingredients": [
{
"$op": "remove",
"name": "Hydrochloric Acid"
}
]
}
Or add it back:
PATCH /products/123
Content-Type: application/json
Accept: application/json
{
"ingredients": [
{
"$op": "add",
"name": "Hydrochloric Acid"
}
]
}
Does anyone has a better way? Is there some standard on the subject?
In my opinion the best solution would be to provide another REST endpoint for product's ingredients management. When you in addition provide links in a HATEOAS manner, you will be able to fully controll that array right after getting a product resource.
Consider this representation:
GET /products/123
Accept: application/json
{
"id": "123",
"name": "Shampoo",
...
"ingredients": [
{
"name": "Sodium Lauryl Sulfate"
"links": [
{
"rel": "self",
"href": "/products/123/ingredients/1"
}
]
},
{
"name": "Sodium Laureth Sulfate",
"links": [
{
"rel": "self",
"href": "/products/123/ingredients/2"
}
]
},
...
],
"links": [
{
"rel": "self",
"href": "/products/123"
},
{
"rel": "ingredients",
"href": "/products/123/ingredients"
}
]
}
Having this you could add new ingredient to a product...
POST /products/123/ingredients
Content-Type: application/json
Accept: application/json
{
"name": "Hydrochloric Acid"
}
...or delete existing one.
DELETE /products/123/ingredients/2
What is the best way to achieve this add / remove operation without having the source array?
If you remove ingredients array from product's JSON representation and leave only link to it you are still able to add new ingredient right away.
Remove operation still need source array but you could download it asynchronously. In fact i see no point in deleting anything from array without having it first. How do you know that ingredient you try to remove is inside?
Best regards
As per the RIPE REST API documentation, one needs to specify the requests in the following format:
http://rest.db.ripe.net/{source}/{objecttype}/{key}
So I am assuming that looking up an IP address will be like this:
http://rest.db.ripe.net/ripe/inetnum/193.0.6.142.json
However, the response I get is :
{
"link": {
"type": "locator",
"href": "http://rest.db.ripe.net/ripe/inetnum/193.0.6.142"
},
"errormessages": {
"errormessage": [
{
"severity": "Error",
"text": "ERROR:101: no entries found\n\nNo entries found in source %s.\n",
"args": [
{
"value": "RIPE"
}
]
}
]
},
"terms-and-conditions": {
"type": "locator",
"href": "http://www.ripe.net/db/support/db-terms-conditions.pdf"
}
}
What am I doing wrong ?
You are using the wrong URL, the correct URL for your example query would be:
http://rest.db.ripe.net/search.json?query-string=193.0.0.0/21&flags=no-filtering
Or this for XML:
http://rest.db.ripe.net/search.xml?query-string=193.0.0.0/21&flags=no-filtering
Looks like https://rest.db.ripe.net/search.json?query-string=193.0.6.142 is the correct link to use. This seems to return back the same data as I see on ripe.net
You didn't write {key} part right. Inetnum objects on RIPE have "193.0.0.0 - 193.0.7.255" type of key. You must make a request like this:
https://rest.db.ripe.net/ripe/inetnum/91.123.16.0 - 91.123.31.255
Using Wordpress's plugin WP REST API version 1, there is an endpoint called /users/me which response with data for the currently logged-in user. When I requested /users/me I got 403 Request Forbidden error. But If I requested /users/1 (where 1 is the user ID) then everything works. So why am I getting 403 error for /users/me endpoints? I'm using Postman to send my request:
THIS WORKS (userID 1 is the currently logged-in user):
http://example.com/wp-json/users/1?access_token={myAccessToken}
DOESN'T WORK:
http://example.com/wp-json/users/me?access_token={myAccessToken}
However, when using WP REST API version 2, /users/me works but it only returns a subset of what version 1 would have returned. The data is incomplete by comparison (i.e. email, first name, last name ...etc)
http://example.com/wp-json/wp/v2/users/me?access_token={myAccessToken}
{
"avatar_urls": {
"24": "http://2.gravatar.com/avatar/29b3ef85f13fedb43f84e6cb4a634e73?s=24&d=mm&r=g",
"48": "http://2.gravatar.com/avatar/29b3ef85f13fedb43f84e6cb4a634e73?s=48&d=mm&r=g",
"96": "http://2.gravatar.com/avatar/29b3ef85f13fedb43f84e6cb4a634e73?s=96&d=mm&r=g"
},
"description": "",
"id": 1,
"link": "http://example.com/author/admin/",
"name": "admin",
"url": "",
"_links": {
"self": [
{
"href": "http://example.com/wp-json/wp/v2/users/1"
}
],
"collection": [
{
"href": "http://example.com/wp-json/wp/v2/users"
}
]
}
}