I have a Stock resource which is obviously an item of stock and it can be accessed by..
[Get] /stock/{stockId}
And I have a printer resource which is a network printer somewhere and it can be accessed by..
[Get] /printer/{printerId}
And I have a Template which points to a template file on the server
[Get] template/{templateId}
Now what I want to do is be able to send a request to a printer to print a certain stock item using a certain template.
My first thought would be
/printer/{printerId}/printstock?stockId=1&templateId=1
So my questions are -
When it finishes printing it will update the stock item to say it has been printed does this mean it should be a POST (or should it be a PUT?)
Are actions such as the "printstock" in the URL the correct way to go about this?
Should Stock be part of the main Url rather than in the querystring?
Model the print job as a separate resource. You create a new print job by POSTing to a collection resource that represents all print jobs.
Request:
POST /printjobs
Content-Type: application/json
{
"printer": 1234,
"stock": 1,
"template": 1
}
Response:
201 Created
Location: /printjobs/42
Then your client could GET the state of the print job.
GET /printjobs/42
200 OK
Content-Type: application/json
{
"id", 42,
"state": "PRINTING",
"printer": 1234,
"stock": 1,
"template": 1
}
After the job has finished, the sate could change to PRINTED and the state of the stock could change in a similar way.
Related
Is it ok to return extra information in http PUT response such as createdDateTime or lastUpdateTime
E.g. PUT request comes as follows
properties
{
"name": "somename"
"addr": "someaddr"
}
In response along with sending the resource representation I am sending extra information
HTTP OK or CREATED
properties
{
"name": "somename"
"addr": "someaddr"
"lastUpdateTime": "somedatetime"
}
Is this a bad practice ?
I see no problem with that. If the client needs that information, then the resource will have to include it as a property. The client can POST/PUT without it (NULL), or the server will ignore it anyway (since this is only set server-side), but it will have to reflect it afterwards.
You can always secure your API if you're going to expose it publicly (OAuth, API keys etc).
This is my Rest service to update list item
URL: https://site/_api/lists/getbytitle('Test')/items(49)
Header
X-RequestDigest: some unique id from contextinfo post service
Content-Type: application/json;odata=verbose
X-HTTP-Method: MERGE
IF-MATCH: 49
Body
{
"__metadata": {
"type": "SP.Data.TestListItem"
},
"Title": "Title all1",
"Option1": "Updated 2"
}
When I run this URL in post man I get an error
The request ETag value __metadata.etag does not match the object's ETag value
"8".
But If I change IF-MATCH value in header as *, it's updating properly. Why I am getting an error if use ETag?
You are using the ETag incorrectly. The ETag will correspond to the item's Version not the item's ID.
The best way to test this is to do a get request for the item and look at the metadata for the ETag property. You will see something similar to this
{
"__metadata": {
"id":"Web/Lists(guid'xxxxxxxx')/Items(1)",
"uri":"https://site.sharepoint.com/site/subsite/_api/Web/Lists(guid'xxxxxx')/Items(1)",
"etag":"\"12\""
}
}
Notice the formatting of the ETag.
I can't think of any good reason to use the IF-MATCH for a specific ETag in the case of updating the item. The request parameter for the ID should be more than sufficient. Checking versioning with ETags is needed when wanting to PUT, MERGE, or DELETE a specific version of an item.
Check this Working with lists and list items with REST for more information.
In context of an event management system where speakers are talking at different sessions. My entities are Speakers and Sessions
Let's say the endpoint is
1) POST /speakers (to insert detail of a speaker ONLY)
2) POST /speakers (to insert detail of speaker + id of the session he's talking on)
point 2 requires to do an additional insert in the join table.
How can I specify both kinds of operations within the same endpoint.
A speaker could be represented including the session he speaks on. For example:
{
"id": 1234,
"firstname": "Joe",
"lastname": "Doe",
"sessions": []
}
This representation means that the speaker is not speaking on any session. sessions is an empty array. Doing
POST /speakers
Content-Type: application/json
with the JSON body as show above, would create the speaker.
If the client knows in advance all sessions the speaker will be speaking, the JSON could look like this:
{
"id": 1234,
"firstname": "Joe",
"lastname": "Doe",
"sessions": [
{
"id": 12,
"link": "/session/12"
},
{
"id": 34,
"link"; "/session/34"
}
]
}
For each session the speaker is speaking on, a short object consisting only of the id and a link to the session are included. This should be enough for the server to know how to link speaker and sessions in the database.
Now let's consider the case, that the sessions a speaker will speak on are not known in advance by the client. The client would create the speaker using the first JSON representation above including an empty sessions array. Later, when all sessions the speaker will speak on are known to the client, he would make a PATCH request:
PATCH /speakers/1234
Content-Type: application/json
{
"sessions": [
{
"id": 12,
"link": "/session/12"
},
{
"id": 34,
"link"; "/session/34"
}
]
}
Note that now we only send the sessions. All other attributes of the speaker shall be left as is on the server.
If the client wants to add sessions to the speaker one after the other, he could do this for every session:
POST /speakers/1234/sessions
Content-Type: application/json
{
"id": 43,
"link": "/sessions/43"
}
This would mean: "add session 43 to the list of sessions of speaker 1234". here /speakers/1234/sessions is a sub resource of /speaker/1234. Adding to it makes sense (of course the server would have to check for duplicates).
Note the different usage of POST to create a new resource (a speaker), to add to a sub resource (the list of sessions). Note also that changing only part of a resource (the speaker) uses PATCH.
Edit:
The HTTP verb PUT is usually used if the client wants to send the complete representation of a resource. When adding the list of sessions to an existing speaker, we use PATCH on the speaker because using PUT on him would require the client to send a complete representation of the speaker. In this use case the client does not want to do this, he wants to set the list of sessions.
An alternative way could be to
PUT /speakers/1234/sessions
Content-Type: application/json
[
{
"id": 12,
"link": "/session/12"
},
{
"id": 34,
"link"; "/session/34"
}
]
with a complete list of sessions on the subresource sessions. Note the difference: here the client is sending a complete representation of the list of sessions for the speaker. Here PUT means: "Overwrite the complete list of sessions for this speaker with what I provide".
Using /speakers?eventId=1 to get the list of speakers for even 1 is good practice. Here the client requests a filtered subset of the collection resource /speakers. Using query parameter to express filter conditions is very common.
About good resources for this kind of knowledge my general advice is to always think about resource. What are the resources your API provides? How are different types of resources related? Can they exist next to each other (a speaker can exist without a session, a session can exist without a speaker), or are the composites (a hotel room can only exist inside a hotel). Usually this kind of question helps. But in REST there are no hard rules or "standards" for how URLs must be constructed. I think it is important to be consistent in an API.
The HTTP/1.1 standard states that if a POST operation results in the creation of a resource, then the response should include a Location header with the address of the new resource.
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see section 14.30).
and in section 14.30,
For 201 (Created) responses, the Location is that of the new resource
which was created by the request.
Now suppose that my API allows batch creation of resources by POSTing an array to the collection resource URL. For example:
POST /books
[
{
"name": "The Colour of Magic",
"published": "1983"
},
{
"name": "The Light Fantastic",
"published": "1986"
}
]
Since two \book\{bookId} resources have been created, what should be the value of the Location header in this case?
The question Http post response after multiple new resource creation? is similar, but it asks about the response entity, not the headers (and is unanswered).
RFC 2616 is obsolete. Stop looking at it except for historical purposes.
The current spec, RFC 7231, says:
"If one or more resources has been created on the origin server as a result of successfully processing a POST request, the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created (Section 7.1.2) and a representation that describes the status of the request while referring to the new resource(s)." -- http://greenbytes.de/tech/webdav/rfc7231.html#POST
And yes, that doesn't help a lot when there isn't a "primary" resource.
I know this answer is late to the party but I believe the best solution is to create a new "Batches" resource with a uuid identifier that would return the list of Book URLs that were added using a URL like this:
http://api.example.com/batches/{uuid}
e.g.
http://api.example.com/batches/2b9b251f71a4b2901d66e04725bc0c9cb5843c74
Then your POST or PUT can return the above URL on it's Location: {url} header and a 201 - Created status code.
If you then GET that URL that resource should respond with a representation that lists the URLs created in that batch, as well as any other info about the batch such as its uuid and the time/date it was created.
{
"uuid": "2b9b251f71a4b2901d66e04725bc0c9cb5843c74",
"datetime": "2005-08-15T15:52:01+00:00",
"books": [
"http://api.example.com/books/the-colour-of-magic",
"http://api.example.com/books/the-light-fantastic"
]
}
Those resources could then have a TTL of an hour or a month, whatever you choose. Or they could live forever if you want; whatever your use-case requires.
I think that you are in a particular use case for the header Location. In the case of bulk creation, the result of the processing is generally provided within the returned content itself. As a matter of fact, the processing can be completely or partially successful. I mean all elements were added or only a subset and the result shows to the end-user what actually happens.
So I think that the header Location isn't usable in such context. I see two options for the status code:
The status code is 201 if at least one element is created)
The status code is 200 to tell that the bulk request globally succeeds but the result of each operation is described in the response content.
You can however notice that a status code 202 exists if your resource handles the bulk creations in an asynchronous way. But in the context, you need then to pull a resource to get the status of the inserts.
Regarding the content of the response, you are free to choose. We could imagine something like that:
{
"took": 4,
"errors": true | false,
"items": [
{ "added": true,
"error": null
"id": "123"
},
{ "added": false,
"error": {
"code": "err12",
"description": "validation error (field type, ...)"
}
"id": null
}
]
}
ElasticSearch provides such bulk api with create but also update and delete support - see this link for more details: http://www.elastic.co/guide/en/elasticsearch/guide/current/bulk.html.
Here are similar questions that could give some hints:
How to Update a REST Resource Collection
REST API - Bulk Create or Update in single request
Hope it helps you,
Thierry
I am trying to understand a little bit more about the REST ways :). Let's say I have a collection of ProductTypes that one can retrive via url GET /productTypes and let's say that we can but don't have to apply any filter. So this fetches 500 records.
Now if I want to do full update of the resource I could use PUT or POST at /productTypes/123. So far so good.
If I am creating a new resource and I know the id ahead of time, I would use PUT at /productTypes/123 and return 201 otherwise for update PUT with 200.
If I do partial update of the resource I would do PUT or POST at /productTypes/123/displayOrder and return 303 indicating that some other resource has been modified.
But what if I do 1 POST sending in basically a list of Key-Value pairs of product Id and display order, and I modify 5 out of 500 records. How do I indicate now that these 5 records have changed?
What happens with GET at /productTypes now after this partial update. I read somewhere that instead of returning multiple records with this get, I should return the list links to the resources, and then fetch them one by one, as that would allow for insane caching. But still how do I indicate that 5 records have changed? Do I need to do 5 separate posts with 303, or is there different mechanism. Hope this makes sense.
I don't see anything in the spec that specifically bars you from using multiple Content-Location headers. I tested it out and Chrome's totally OK with it. It won't automatically redirect for you, but you don't want that anyway with multiple resources involved.
HTTP/1.1 303 See Other
Content-Location: /productTypes/123/displayOrder
Content-Location: /productTypes/456/displayOrder
Content-Location: /productTypes/789/displayOrder
Content-Location: /productTypes/012/displayOrder
Content-Location: /productTypes/345/displayOrder
I'd do this:
PATCH /productTypes HTTP/1.1
Content-Type: application/json
{"item":[
{"id":"1","displayOrder":"4"},
{"id":"2","displayOrder":"2"},
{"id":"3","displayOrder":"1"},
{"id":"4","displayOrder":"3"},
{"id":"5","displayOrder":"5"}
]}
HTTP/1.1 200 OK
Content-Type: application/hal+json
{
"_links": { "self": {"href": "/productTypes" } }
"_embedded": {
"item": [{
"_links": { "self": { "href": "/productTypes/1" } },
"displayOrder": "4"
},
/* 4 more entries */
]
}
}