3 ms·
One thing this piece leaves out is that if the operation/creation is in fact expensive, you want to make sure you have some kind of two-phase option so you don'
by epaulson 8y ago
One thing this piece leaves out is that if the operation/creation is in fact expensive, you want to make sure you have some kind of two-phase option so you don't inadvertently create multiple copies.
If the client crashes after the POST to create 'death star' succeeds and hence construction starts, but before it can read the response of the POST in the example and so never gets the pointer to the /queue/12345 from the response, if the client reissues the POST in the server should reject a second attempt to create a star named 'death star' just and give back the same pointer to /queue/12345. Or, if you want to be able to have two stars named 'death star', you should first POST to some endpoint to get a unique identifier from the server first, and then use that to kick off the creation of your death star so the client can reason about the current state.
- Anderkent 8y agoOr you could just generate an unique identifier on the client and save the roundtrip? Uuids aren't really expensive.
- farazbabar 8y agoUUID is not enough to prevent duplicate resource creation. Consider the following steps: 1. Receive a request with uuid, 2. Persist the fact that system received this request, 3. who or what processes it? Even if you are working off atomic persistence, the resource creation process (the kick-off process) needs to maintain the state that it plucked one off the queue or table, atomically update the state in persistence as it creates the resource somewhere else and log the successful creation of this resource as yet another entry in the persistence store. This way, requests that exceed their SLA can be retried and the downstream systems must act with correct idempotent behavior in order for all of this to work correctly in the presence of failures. It is all very technically possible, but it goes beyond just a UUID (in other words, UUID is necessary but not sufficient).
- Anderkent 8y agoThe issues you list don't really seem to be relevant in regard to duplicate resource creation? They're just about handling creating the resource in the first place. As long as the uuid is persisted you can redirect all attempts to recreate that id to the right job/queue/whatever actually backs resources.
- _hyn3 8y agoYou would use PUT in the instance where you have the same id (in other words, the same resource representation/URL), and PUTs should be idempotent, meaning that you can re-attempt creation multiple times without side effects. POSTs should not be idempotent. It shouldn't be expensive to generate a new ID, so you can just return the new ID/URL and then the client can check to see if/when that ID is created. An important factor in REST is that it moves state processing to the client. The clients need to track transactions, not the server. The servers don't have a concept of a session like old-school web apps did. Any state (like an ID that was just created) should be tracked on the client. Either a 202 Accepted for that ID resource that's not yet created, or a 4xx level error (4xx mean 'retry, this is not a permanent failure') such as 423 Locked could be appropriate while you are actually generating that resource.
- geezerjay 8y ago> if the client reissues the POST in the server should reject a second attempt to create a star named 'death star' just and give back the same pointer to /queue/12345. This use case is typically handled by replying to the duplicate POST request with a status code 409 Conflict, and include in the response a link to the resource representing the long-running job. https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10 https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec1...
- agopaul 8y agoThis. Too bad many APIs around are designed without keeping in mind that timeouts and double submissions can occur. A few years ago I had to integrate with another software vendor (using SOAP, sigh), and development went all smooth, testing too but when the integration went live we noticed that the VPN connection was somehow not working properly and we were getting 20% packet loss. Luckily, for each API call that would write data we would issue a unique "requestId" and implemented retry logic so double submissions (eg. due to timeouts) were discarded. Needless to say, that saved our day and the project went smoothly even though it took a week to the DevOps guy to debug and fix the faulty VPN tunnel.