Should we always validate resource id in url and body in HTTP PUT request? - api

Suppose I am updating a employee record
url - /api/employees/10
body -
{
id : 10,
name : xyz
}
Should I validate for the employee id in url is same as in response? Because one employee can hit the url himself but update the data of another employee by sending another value in the PUT body.

If you have to validate, it's likely that you want to use POST. A POST is not idempotent and you are supposed to manage the change.
PUT is idempotent, and it just creates a resource. It implies that you don't actually care what id 10 is and whether it is a new id or an existing id. You just replace id 10 with the resource you supply. You only use PUT when you know what the uri should be.

Yes, if the representation of the object in the body contains its own key, you should validate that it matches the key from the URL. It's an error for the client to try to PUT an object at /api/employees/10 that isn't a valid value for employee #10's record, so you should check for that and report it as an error just as you would check that the object has correct syntax.
I believe that the best error code to return in this case is 422 Unprocessable Entity, but I might be wrong about that.
Another thing you can do instead is don't include the key at all in the body. However I find that keeping the key in makes sense for consistency with the way the same type of object is represented in other parts of the API (possibly embedded inside other objects). This is especially true when using XML (although it looks like you are using JSON here).

Related

How to use numeric chat IDs to avoid expensive `get_entity(channel_name)` calls?

As per this comment, I'm trying to use numeric channel IDs in my telethon code, so that I don't end up spamming the Telegram API with expensive name lookup calls and getting throttled, but I'm having some difficulty.
e.g. assuming I've already instantiated and connected client:
messages = client.get_messages(numeric_channel_id)
...fails with this error:
ValueError: Could not find the input entity for PeerUser(user_id=[numeric_channel_id]) (PeerUser)
I think there's some cacheing going on, because if I do a get_entity call using the account name first, then the get_messages call works. i.e. something like this:
client.get_entity(channel_name_which_belongs_to_numeric_channel_id)
messages = client.get_messages(numeric_channel_id)
That works just fine, but now I'm doing the expensive get_entity(name) call which is what I'm trying to avoid (because it will result in FloodWaitError problems).
Is there any way I can use the numeric ID of a channel to avoid the expensive get_entity call, in this scenario?
I've also tried forcing the entity type to Channel, like this:
channel = Channel(id=numeric_channel_id, title=None, photo=None, date=None)
messages = client.get_messages(channel)
...but the results are the same, except that the error mentions PeerChannel rather than PeerUser
ID usage is not going to work unless you cached the target as you stated, that's the only way to use the integer id.
you must have met the entity from events or manual requests (say, username fetching).
you should be using client.get_input_entity('username')
it will try to search the local cache first for the saved id + hash that equals the passed username, if found it won't do ResolveUsername (heavy one) and use the local access_hash + id and return you an inputPeer. you pass that to any request you want.
you mustn't use id alone unless you're certain you have met its holder, in other words, id you use has to be something you found out from within the library and within the same session, not something you knew/found out externally.
There is no magical way to fetch something with id you claim you know, if you actually know it, the lib has to create (when the access_hash is present) an InputPeer
As the other answer states, fetching by username will always work but is expensive. However note that such a call will fill the cache so it can later be fetched again much more cheaply by ID.
If you really need a stable reference to some entity and cannot rely on the session cache, and want to avoid usernames, the documentation for Entities vs. Input Entities may be helpful.
What it boils down to is, you can do this:
print(await client.get_input_entity('username'))
...which will show something like:
InputPeerChannel(channel_id=1066197625, access_hash=-6302373944955169144)
...and then, the account that made the get_input_entity call will always be able to use the printed result, without the need for it to be in cache:
from telethon.tl.types import InputPeerChannel
USERNAME = InputPeerChannel(channel_id=1066197625, access_hash=-6302373944955169144)
# ...
await client.send_message(USERNAME, 'Hi') # works without cache

How to pass multiple parameters in #PUT method?

I have a requirement to implement a method like this in Apache CXF JAX-RS(in a concurrent scenario)
#PUT
#Path("/customers/123")
public void updateConcurrentCustomer(Customer existingCustomer,Customer updatedCustomer,boolean forceUpdate){
......
}
In request body, i need to call this method something like this (no root element).
<Customer>
.....existing data....
</Customer>
<Customer>
......updated data....
</Customer>
<boolean>true</boolean>
How this data binding can be achieved?
I tried creating a composite wrapper Resource class like this
#XmlRootElement
public class CustomCustomer implements java.io.Serializable
{
private Customer existingCustomer;
private Customer updatedCustomer;
private boolean forceUpdate;
.....
.....
}
It works well. But i dont want to create this wrapper class.
My concurrency scenario:
customer123 object is in state A.
user1 changes customer123 to state B.
user2 changes customer123 to state C.
user3 changes customer123 to state D. (all at same time)
only high priority user sets forceUpdate flag and finally that update will be overwritten than others.
existingCustomer - will be used to detect conflict changes. It will be in state A
According to the definition
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.
So first of all your customer needs a unique identifier like /customers/{id}. Otherwise the server can't know where the resource should be stored.
Then you don't need to pass the existingCustomer. Either there is none (new resource) or the server already knows him (because you addressed him with a unique URL).
The forceUpdate is also not senseful here. A PUT should modify if the resource already exists so forceUpdate is true be definition.
Sometimes you can't use the clear semantics of a PUT. For instance if the client does not know the id and you don't want that the client chooses one (he can't guarantee uniqueness). Then you can use a POST and the server will return the Location where he stored the Resource.
Also if you want to update only in special cases maybe depending on some other parameters a POST is the appropriate Method.

Can't understand some basic REST stuff

Suppose my model is:
User:
id
nickname
I have a collection /users/
I want the Users to be retrieved by /users/{id} and not /users/${nickname}, because in some more complex cases, there could be no "logical unique constraint".
So the basic JSON payload I could use is for exemple:
{
id: 123,
nickname: 'someUserName'
}
Nothing fancy here.
POST on /users/
As far as I know, an user as an identifier. It is part of the resource representation, so it should be in the payload (?).
Put what if I want to generate the ID myself on the backend, using a DB sequence for exemple?
Then my payload becomes:
{
nickname: 'someUserName'
}
Is this appropriate?
What is supposed to be the output of this POST? Nothing? Just a header referencing the resource location, including the ID?
GET on /users/id
When we get the resource, we load its content as JSON:
{
id: 123,
nickname: 'someUserName'
}
PUT on /users/id
As far as I know, the payload used on this method is supposed to "override" the resource content. If we wanted partial updates, we would have used PATCH.
But what if I do:
PUT /users/123
{
id: 456,
nickname: 'someUserName'
}
Does this mean that we want to update the id of a resource?
Isn't it kind of redundant to use the id in both the URI and the payload?
Actually I don't really know how to handle the id.
I don't know if I am supposed to use the same resource representation in all POST / PUT / DELETE operations.
I don't know if the id should be part of the unique(?) resource representation.
But if the id is not part of the representation, then when I list the users, using GET /users/, if the ids are not returned, then I don't know how the client can get the user ids...
Can someone help me? :)
First of all
It is not REST if you don't use HATEOAS
I hope you understand this, I'll come back to that at the very end.
POST on /users/
It perfectly ok to not use an ID in the POST payload. If an ID is present react with an error message, so developers understand they are doing wrong.
Therefore only the nickname as a payload is perfectly valid if you don't have anything else in your user resource
The output of your server should include three important things:
HEADER: A status code indicating success or failure (usually 201 Created)
HEADER: The location of the newly created resource (just Location: /path/to/resource)
BODY: A representation of the created resource. Give back a complete payload like on a GET!
GET
perfectly valid
PUT
your analysis regarding PUT/PATCH matchs the spec, the new resource should be identical to the payload meaning the user wishes to change the id if it differs. if a payload contains values which shouldn't be changed (like the ID) you have two possibilities:
Ignore the ID in the payload
Return an error
In both cases inform the user about what you did and what went wrong. I prefer to send/get a 400 Bad Request. If a privileged user could change the ID but the particular user can't an 403 Forbidden may be more appropriate.
Also make sure to document your APIs behaviour. You may allow the ID to be omitted in your API. Don't forget to treat IDs given in a POST payload in a consistent way!
Overall questions
REST operates over Resources.
/users/ is an example for an collection of resources
/users/{id} is an example for a single resource
You should always use the exact same representation in each and every response. If for some reason it is more appropriate to give only a snippet of the information add metadata (link) pointing to the full resource representation.
The ID is always present except in the first POST request of an user.
POST implies that the future location of the resource is not known and has to be provided by the server.
This also means that GET /users/ should return the IDs for each resource.
As always in APIs return strict and be forgiving in requests. document your behaviour so users can learn.
HATEOAS
The true beauty of REST comes to daylight if you implement HATEOAS (Hypermedia As The Engine Of Application State). Part of this means that you should sugar your representations with useful tag/link combinations. This way clients never have to construct an url anymore.
An Example using HAL for your user representation would be:
{
"_links:" {
"self": { "href": "http://yourrest/users/123" }
},
"id": "123"
"nickname": "someUserName"
}
A nice wrapup of using HAL was written by Matthew Weier O'Phinney in his blog when he developed a ZF2 REST Module (first entry is completly zf free, only explaining HAL).
I'm interpreting your descriptions as saying that the id is not part of the resource, it's a unique identifier of the resource. In that case, it should not be part of the payload for any operation.
POST /users with payload {"nickname": "somebody"} would create a new resource with a URL returned in the Location header. That URL would presumably look like /users/123 but from the client's point of view there's no reason to expect that. It could look like /something/else/entirely.
GET /users/123 would (assuming that URL was returned by an earlier POST) return the payload {"nickname": "somebody"}.
PUT /users/123 would (with the same assumption as above) replace the resource with the payload you send with the PUT, say {"nickname": "somebody else"}.
If you want the client to be able to name a resource, then you'd also let PUT /users/123 create a new resource with that URL.
I know of no common RESTful way to rename a resource. I suppose a POST with the old URL as part of the query part or the body would make sense.
Now, suppose I'm wrong and you do want id to be part of the resource itself. Then every payload would include it. But from the client's point of view, there should be no assumption that "id": 123 implies that the URL would be /users/123.
Finally, all of this is from a fairly purist point of view. There is value to thinking of URLs as the only real identifier of a resource, but it's not awful to break that rule and have the client use logic to create the URLs.

Proper resource names of a REST API

Let's say we are making an invoice API. What is a more appropriate resource?
GET
paid_invoices
due_invoices
all_invoices
or
GET
invoices/all
invoices/due
invoices/paid
Additional question: If your API allows marking invoices as paid what's the proper resource?
PUT //where 3 is the id
invoices/3
or
PUT
pay_invoice/3
I would say:
GET /invoices returns all invoices;
A filter can return either paid or due invoices: GET /invoices?state=paid where state can be paid or due.
To mark an invoice as paid, you can either set the corresponding state to your resource, and then you just have to update (replace actually) it using PUT /invoices/<id>.
Alternatively, you can patch your resource: PATCH /invoices/<id>. This method requires a diff like state=paid for example.
It's just a matter of what you want to send to your API (a complete resource, or just the change to apply).
A non-REST solution could be to perform a PATCH request to /invoices/<id>/paid. It's not pure REST but it's ok.

Restlet using Get and Post Methods

Hiiii,
I am developing a small app using Restlet 2.0 API..
I want just to know how to create a URI which accepts more than one parameter for insert query.
Ex:
router.attach("/{patient}/insertpatient", insertpatient);
I want to insert all the info about the patient using POST.
Or Search by ID and address for instance using GET.
thanks,
For the "insert patient" operation, I'd suggest something like a POST to /patients (if the server generates the patient ID) or a PUT to /patients/{patient-id} (if the client generates the patient ID). Either way, the body of the message would contain all of the input data needed to create a new patient entity. Two simple options for serializing the data would be as a URL-encoded form or as JSON.
Lookup by by ID could be a simple as a GET on /patients/{patient-id}. Lookup by address could also be a GET, possibly using a URL-encoded query parameter. For example, you could fetch the patient at address "123 Main Street, apt 4, Anytown, USA, 98765" with a GET on /patients?addr=%20Main%20Street%2C%20apt%204%2C%20Anytown%2C%20USA%2C%2098765