I am looking to expose some domain RESTful APIs on top of an existing project. One of the entities I need to model has a single document: settings. Settings are created with the application and is a singleton document. I'd like to expose it via a well-designed resource-based RESTful API.
Normally when modeling an API for a resource with many items its something like:
GET /employees/ <-- returns [] of 1-* items
GET /employees/{id}/ <-- returns 1 item
POST /employees/ <-- creates an item
PUT /employees/{id}/ <-- updates all fields on specific item
PATCH /employees/{id}/ <-- updates a subset of fields specified on an item
DELETE /employees/{id}/ <-- deletes a specific item
OPTION 1: If I modeled settings in the same way then the following API is built:
GET /settings/ <-- returns [] of 1-* items
[{ "id": "06e24c15-f7e6-418e-9077-7e86d14981e3", "property": "value" }]
GET /settings/{id}/ <-- returns 1 item
{ "id": "06e24c15-f7e6-418e-9077-7e86d14981e3", "property": "value" }
PUT /settings/{id}/
PATCH /settings/{id}/
This to me has a few nuances:
We return an array when only 1 item CAN and EVER WILL exist. Settings are a singleton that the application creates.
We require knowing the id to make a request only returning 1 item
We require the id of a singleton just to PUT or PATCH it
OPTION 2: My mind then goes in this direction:
GET /settings/ <-- returns 1 item
{ "id": "06e24c15-f7e6-418e-9077-7e86d14981e3", "property": "value" }
PUT /settings/
PATCH /settings/
This design removes the nuances brought up below and doesn't require an id to PUT or PATCH. This feels the most consistent to me as all requests have the same shape.
OPTION 3: Another option is to add the id back to the PUT and the PATCH to require it to make updates, but then an API user must perform a GET just to obtain the id of a singleton:
GET /settings/ <-- returns 1 item
{ "id": "06e24c15-f7e6-418e-9077-7e86d14981e3", "property": "value" }
PUT /settings/{id}/
PATCH /settings/{id}/
This seems inconsistent because the GET 1 doesn't have the same shape as the UPDATE 1 request. It also doesn't require a consumer to perform a GET to find the identifier of the singleton.
Is there a preferred way to model this?
Does anyone have any good reference material on modeling RESTful APIs for singleton resources? I am currently leaning towards OPTION 2 but I'd like to know if there are good resources or standards that I can look into.
Is there a compelling reason to require an API consumer to make a GET for the id of a resource to then use it in an update request, perhaps for security reasons, etc?
The ID of the Resource is the Url itself and not necessarily a Guid or UUID. The Url should uniquely IDentify the Resource, in your case the Settings entity.
But, in order to be RESTfull, you must point to this resource in your index Url (i.e. the / path) with an appropriate rel attribute, so the client will not hardcode the Url, such as this:
GET /
{ ....
"links": [
{ "url" : "/settings", "rel" : "settings" }
], ...
}
There are no specifics to accesing a singleton resource other than the Url will not contain a Guid, Uuid or any other numeric value.
Option 2 is perfectly RESTful, as far as I can tell.
The core idea behind RESTful APIs is that you're manipulating "resources". The word "resource" is intentionally left vague so that it can refer to whatever is important to the specfic application, and so that the API can focus only on how content will be accessed regardless of what content will be accessed.
If your resource is a singleton, it does not make sense to attribute an ID value to it. IDs are very useful and commonly used in RESTful APIs, but they are not a core part of what makes an API RESTful, and, as you have noticed, would actually make accessing singleton resources more cumbersome.
Therefore, you should just do away with IDs and have both
GET /settings/
and
GET /settings/{id}
always return the settings singleton object. (access-by-id is not required, but it's nice to have just in case someone tries it). Also, be sure to document your API endpoint so consumers don't expect an array :)
Re: your questions,
I believe option 2 would be the preferred way of modeling this, and I believe requiring your consumer to make a GET for the id would actually be somewhat of an anti-pattern.
I think the confusion here is because the word settings is plural, but the resource is a singleton.
Why not rename the resource to /configuration and go with option 2?
It would probably be less surprising to consumers of your API.
You're probably overthinking it. There's no concept of singleton in HTTP or REST.
GET /settings/ is perfectly fine.
By the way, we can hardly relate this to DDD - at least not if you don't give more context about what settings means in your domain.
It might also be that you're trying to tack an "Entity with ID" approach on Settings when it's not appropriate. Not all objects in a system are entities.
Related
I've seen many examples of HATEOAS where every resource has links to related resources. An API that returns N items of a certain resource per page, the client would probably need N calls to fetch any nested resource by consuming HATEOAS. For example:
GET city/documents:
[{
id: 1,
city: {
self: 'http://service.com/cities?filter=id==1'
},
document: { ... }
...
}, {
id: 2,
city: {
self: 'http://service.com/cities?filter=id==2'
},
document: { ... }
...
}]
FYI, the query parameter uses the FIQL syntax to define the filters.
Now, if the client was to fetch the city details for each document (to show on UI), it will probably need N additional calls. However in my case, the /cities API can additionally take multiple city ids like this: /cities?filter=id=in=(1,2) that can reduce N calls to one. Is there a way to articulate something like this using HATEOAS? I've read about the templates but not sure how should the template look like and how would client consume it?
I've seen many examples of HATEOAS where every resource has links to related resources. An API that returns N items of a certain resource per page, the client would probably need N calls to fetch any nested resource by consuming HATEOAS.
Yes. Less true in a world with Server-Push, where the server can proactively provide multiple resources in response to a query. If you imagine asking for a web page, and getting the html, and then also the images and the java script resources too, then you've got the right sort of idea.
API can additionally take multiple city ids like this: /cities?filter=id=in=(1,2) that can reduce N calls to one. Is there a way to articulate something like this using HATEOAS?
Yes.
Let's walk through it carefully. What you've done here is introduced a new resource, with identifier /cities?filter=id=in=(1,2). You might have another resource /cities?filter=id=in=(1,20) and another resource /cities?filter=id=in=(1,2000). In your implementation, these might be a "single endpoint" that extracts parameters from the identifier and uses them to generate the correct representation.
So what you get is something like a data transfer object - a large grained resource fetched in a single go.
I've read about the templates but not sure how should the template look like and how would client consume it?
The simplest example, which you have likely seen already, is a web form. You allow the client to provide the start and end elements, and the form processing takes that information and creates the specified URI from it.
/filtered-cities?start=1&end=2000
So the client needs to understand what the form is for, and how to identify the semantics of the different elements in the form. The agent needs to understand the processing rules that transfer the form data into the URI.
URI Templates are the same basic idea; they give you a domain agnostic language with which to describe where the parameters go in a resource identifier. The basic pattern is the same - there needs to be agreement about the semantics of the parameters, the server provides a URI, the client provides a parameter map, and the generic code can take care of the merge
uri = template.apply(parameterMap)
URI Templates aren't quite as powerful as forms; with a form, you can introduce a default value for a parameter, but there is no analogous capability in URI templates.
HAL-Forms may give you a better sense of how a form based approach might work in JSON.
I would like to know which is the best practice when you are having a resource which contains a list of subresources. For example, you have the resource Author which has info like name, id, birthday and a List books. This list of books exists only in relation with the Author. So, you have the following scenario:
You want to add a new book to the book list
You want to update the name of a book from the list
You want to delete a book from the list
SOLUTION 1
I searched which is the correct design and I found multiple approaches. I want to know if there is a standard way of designing this. I think the design by the book says to have the following methods:
To add: POST /authors/{authorId}/book/
To update: PUT /authors/{authorId}/book/{bookId}
To delete: DELETE /authors/{authorId}/book/{bookId}
SOLUTION 2
My solution is to have only one PUT method which does all these 3 things because the list of books exists only inside object author and you are actually updating the author. Something like:
PUT /authors/{authorId}/updateBookList (and send the whole updated book list inside the author object)
I find multiple errors in my scenario. For example, sending more data from the client, having some logic on the client, more validation on the API and also relying that the client has the latest version of Book List.
My question is: is it anti-pattern to do this?
SITUATION 1. In my situation, my API is using another API, not a database. The used API has just one method of "updateBookList", so I am guessing it is easier to duplicate this behavior inside my API too. Is it also correct?
SITUATION 2. But, supposing my API would use a database would it be more suitable to use SOLUTION 1?
Also, if you could provide some articles, books where you can find similar information. I know this kind of design is not written in stone but some guidelines would help. (Example: from Book REST API Design Rulebook - Masse - O'Reilly)
Solution 2 sounds very much like old-style RPC where a method is invoked that performs some processing. This is like a REST antipattern as REST's focus is on resources and not on methods. The operations you can perform on a resource are given by the underlying protocol (HTTP in your case) and thus REST should adhere to the semantics of the underlying protocol (one of its few constraints).
In addition, REST doesn't care how you set up your URIs, hence there are no RESTful URLs actually. For an automated system a URI following a certain structure has just the same semantics as a randomly generated string acting as a URI. It's us humans who put sense into the string though an application should use the rel attribute which gives the URI some kind of logical name the application can use. An application who expects a certain logical composition of an URL is already tightly coupled to the API and hence violates the principles REST tries to solve, namely the decoupling of clients from server APIs.
If you want to update (sub)resources via PUT in a RESTful way, you have to follow the semantics of put which basically state that the received payload replaces the payload accessible at the given URI before the update.
The PUT method requests that the state of the target resource be
created or replaced with the state defined by the representation
enclosed in the request message payload.
...
The target resource in a POST request is intended to handle the
enclosed representation according to the resource's own semantics,
whereas the enclosed representation in a PUT request is defined as
replacing the state of the target resource. Hence, the intent of PUT
is idempotent and visible to intermediaries, even though the exact
effect is only known by the origin server.
In regards to partial updates RFC 7231 states that partial updates are possible by either using PATCH as suggested by #Alexandru or by issuing a PUT request directly at a sub-resource where the payload replaces the content of the sub-resource with the one in the payload. For the resource containing the sub-resouce this has an affect of a partial update.
Partial content updates are possible by
targeting a separately identified resource with state that overlaps a
portion of the larger resource, or by using a different method that
has been specifically defined for partial updates (for example, the
PATCH method defined in [RFC5789]).
In your case you could therefore send the updated book collection directly via a PUT operation to something like an .../author/{authorId}/books resource which replaces the old collection. As this might not scale well for authors that have written many publications PATCH is probably preferable. Note, however, that PATCH requires an atomic and transactional behavior. Either all actions succeed or none. If an error occurs in the middle of the actions you have to role back all already executed steps.
In regards to your request for further literature, SO isn't the right place to ask this as there is an own off-topic close/flag reason exactly for this.
I'd go with the first option and have separate methods instead of cramming all logic inside a generic PUT. Even if you're relying on an API instead of a database, that's just a 3rd party dependency that you should be able to switch at any point, without having to refactor too much of your code.
That being said, if you're going to allow the update of a large number of books at once, then PATCH might be your friend:
Looking at the RFC 6902 (which defines the Patch standard), from the client's perspective the API could be called like
PATCH /authors/{authorId}/book
[
{ "op": "add", "path": "/ids", "value": [ "24", "27", "35" ]},
{ "op": "remove", "path": "/ids", "value": [ "20", "30" ]}
]
Technically, solution 1 hands down.
REST API URLs consist of resources (and identifiers and filter attribute name/values). It should not contain actions (verbs). Using verbs encourages creation of stupid APIs.
E.g. I know a real-life-in-production API that wants you to
do POST on /getrecords to get all records
do POST on /putrecords to add a new record
Reasons to choose solution 2 would not be technical.
For requirement #2 (You want to update the name of a book from the list), it is possible to use JSON PATCH semantics, but use HTTP PATCH (https://tools.ietf.org/html/rfc5789) semantics to design the URL (not JSON PATCH semantics as suggested by Alexandru Marculescu).
I.e.
Do PATCH on /authors/{authorId}/book/{bookId}, where body contains only PK and changed attributes. Instead of:
To update: PUT on /authors/{authorId}/book/{bookId}
JSON PATCH semantics may of course be used to design the body of a PATCH request, but it just complicates things IMO.
Lets say I have the following classes:
company
user
address
a company object can contain users and addresses,
a user object contains addresses
company can exist on its own, but users and address is always a part of company or user (a composition in UML wording):
company ->
addresses
users ->
addresses
Now I want use the right REST-structure for POST (insert) and PUT (update) requests. What would be the correct approach?
variant 1:
// insert address:
POST /api/company/{companyId}/addresses
POST /api/company/{companyId}/users/{userId}/addresses
// update address:
PUT /api/company/{companyId}/addresses/{addressId}
PUT /api/company/{companyId}/users/{userId}/addresses/{addressId}
variant 2:
// insert address:
POST /api/address // companyId, userId etc. as parameter
// update address:
PUT /api/address/{addressId}
My personal gut feeling would be to use variant 1 for creation (POST) and variant 2 for updates (PUT), because variant 1 seems "cleaner" for creation but for update variant 2 would be better because it does not require a parentId (company or user)
First, REST is an architectur style not a protocol. This means that there is no right or wrong in how you define your URI. The only requirement Roy Fielding put in place was that each resource has to have a unique resource identifier (URI). The operation you may do on those URIs (verbs) are defined by the underlying hypertext transfer protocol (HTTP).
Second, there are certain best practices like using a sub-resource for resources that are embedded in other resources (especially if they can't exist without the parent resource) as in your case with addresses and users/companies
As you have certain issues with updating a sub-resource:
Usually to update a resource HTTP verb PUT is used which has the limitation of replacing the current state (all the available data) with the state you've sent to the server (in case the update goes well). As there is no partial update yet defined in HTTP some use the PUT verb a bit fuzzy and only update what is available within the request, though issuing a PATCH request and only updating these fields is probably more correct in terms of HTTP specification.
Sub-resources are very similar to regular resources. If you update a sub-resource you don't need to update the parent resource. In your particular case, if you want to update a user's address but not the user itself, you issue a PUT /users/{userId}/addresses/{addressId} HTTP/1.1 request containing the new state of the address to the server. The request body may look like this:
{
"street": "Sample Street 1"
"city": "Sampletown",
"zip": "12345",
"country": "Neverland",
"_links": {
"self": { "href": "/users/{userId}/addresses/{addressId} }
"googleMap": { "href": "https://www.google.com/maps/place/Liberty+Island/#40.6883129,-74.042817,16.4z/data=!4m2!3m1!1s0x0000000000000000:0x005f3b2fa5c0821d" }
}
}
If you want to follow the HTTP PUT verb closely and have dynamic fields, which may appear during runtime, you might have to alter the current table definition eventually, delete the old address entry and insert a new entry with the provided information (depending on the DB layer you are using SQL vs NoSQL). Note the HTTP PUT verb semantic!
On utilizing a fuzzy update strategy (=partial update) a simple update statement should be fine. Here you can simply ignore the additional userId contained within the URI, though this is not (yet) fully HTTP compliant - at least in regards to the spec. In that particular case it is your choice which version of URI you choose, though version 2 only works in the latter case while version 1 works in both cases.
I have an entity with several attributes, say «project». Apart from simple attributes, the project may have a list of «statuses» of which the last one is the current one. I have a web form to create/edit a project. All attributes of this project can be changed in this form, and also users can add a new status for the project (but they can’t change or delete old statuses).
Project statuses are purely composite entities, they don’t have any distinctive meaning or identity outside of the project scope, and they are not to be addressed directly, so they obviously don’t deserve a special root REST resource.
According to REST architecture, I created a resource called /projects. POST is used to create a new project, and PUT is used to change an existing project.
However, I don’t want the client to PUT the project together with all its historical statuses, firstly because this collection is too heavy, and secondly because the business logic allows only for adding statuses, not changing or deleting them, so PUTting the project together with all of its statuses doesn’t make any sense anyway.
PUTting a project with only a new status is also not an option, because it violates the idempotency of PUT.
I also don’t like the idea of POSTing a status in a second HTTP-request, say /project/{id}/status, because that would break the atomicity of the update operation from the user’s standpoint. If this second request gets lost on the wire, then the project will appear inconsistent to the user who edited it (the attributes changed, but the status stayed the same). Creating RESTful "transactions" seems like overkill (and also error prone) for this simple task of updating a seemingly monolithic entity.
This kind of problem is quite ubiquitous in my work, and may be generalized as such: what is the RESTfully correct and atomic way of updating a complex composite entity for which only partial update is allowed by the business logic?
I think that if you want to do partial updates (it's actually your case), you should use the method PATCH. This allows to update either the project without dependencies (statuses) or the dependency(ies) without the project hints.
You can notice that there is a format to describe the operations to do within a method PATCH. It's called JSON Patch (see https://www.rfc-editor.org/rfc/rfc6902). This format describes what you want to do within your request: add an element, update it, remove it, ...
I think that you could have something like that if you want (for example) to update the name of a specific project, remove a status (it's also a sample since I read that you want to forbid this!) and add a new one in one atomic request:
PATCH /projects/1
[
{
"op": "replace",
"path": "/name",
"value": "the new name of the project"
},
{
"op": "remove",
"path": "/statuses/1"
},
{
"op": "add",
"path": "/statuses/",
"value": {
"name": "my status",
(...)
}
}
]
Notice that you can put what you want in the attribute name to identify the related element in the resource state. So /statuses/1 can be the second element in the array, the status with id of value 1 or something else.
The server-side processing for the request can be atomic.
I wrote a blog post about bulk updates: https://templth.wordpress.com/2015/05/14/implementing-bulk-updates-within-restful-services/. I think that the section "Implementing bulk updates" could correspond to what you look for.
Hope it helps you,
Thierry
Do you need HTTP PATCH? It is the verb to express delta updates to a resource.
https://www.rfc-editor.org/rfc/rfc5789
Let's say I want to have a RESTful resource for people, where the client is able to assign ID.
A person looks like this: {"id": <UUID>, "name": "Jimmy"}
Now, how should the client save (or "PUT") it?
PUT /person/UUID {"id": <UUID>, "name": "Jimmy"} - now we have this nasty duplication that we have to verify all the time: Does the ID in body match the one in path?
Asymmetric representation:
PUT /person/UUID {"name": "Jimmy"}
GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}
No IDs in body - ID only in location:
PUT /person/UUID {"name": "Jimmy"}
GET /person/UUID returns {"name": "Jimmy"}
No kind of POST seems like a good idea since the ID is generated by the client.
What are the common patterns and ways to solve it? IDs only in location seems like the most dogmatically correct way, but it also makes the practical implementation harder.
There is nothing wrong in having different read/write models: the client can write one resource representation where after the server can return another representation with added/calculated elements in it (or even a completely different representation - there is nothing in any spec against that, the only requirement is that PUT should create or replace the resource).
So I would go for the asymmetric solution in (2) and avoid the "nasty duplication check" on the server side when writing:
PUT /person/UUID {"name": "Jimmy"}
GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}
If it is a public API you should be conservative when you reply, but accept liberally.
By that I mean, you should support both 1 and 2. I agree that 3 doesn't make sense.
The way to support both 1 and 2 is to get the id from the url if none is supplied in the request body, and if it is in the request body, then validate that it matches the id in the url. If the two do not match, then return a 400 Bad Request response.
When returning a person resource be conservative and always include the id in the json, even though it is optional in the put.
Just FYI, the answers here are wrong.
TLDR; If you're using PUT, you should have the id in the body. If you are using PATCH, you do not need the id in the body.
See:
https://restfulapi.net/rest-api-design-tutorial-with-example/
https://restfulapi.net/rest-put-vs-post/
https://restfulapi.net/http-methods/#patch
PUT
Use PUT APIs primarily to update existing resource (if the
resource does not exist, then API may decide to create a new resource
or not). If a new resource has been created by the PUT API, the origin
server MUST inform the user agent via the HTTP response code 201
(Created) response and if an existing resource is modified, either the
200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate
successful completion of the request.
If the request passes through a cache and the Request-URI identifies
one or more currently cached entities, those entries SHOULD be treated
as stale. Responses to this method are not cacheable.
Use PUT when you want to modify a singular resource which is already a
part of resources collection. PUT replaces the resource in its
entirety. Use PATCH if request updates part of the resource.
PATCH
HTTP PATCH requests are to make partial update on a resource. If you
see PUT requests also modify a resource entity so to make more clear –
PATCH method is the correct choice for partially updating an existing
resource and PUT should only be used if you’re replacing a resource in
its entirety.
So you should use it in this way:
POST /device-management/devices : Create a new device
PUT /device-management/devices/{id} : Update the device information identified by "id"
PATCH /device-management/devices/{id} : Partial-update the device information identified by "id"
RESTful practices indicate that it shouldn't matter what you PUT at /{id}--the content of the record should be updated to the one provided by the payload--but GET /{id} should still link to the same resource.
In other words, PUT /3 may update to payload id to 4, but GET /3 should still link to the same payload (and return the one with id set to 4).
If you are deciding that your API requires the same identifier in the URI and the payload, it's your job to make sure it matches, but definitely use PATCH instead of PUT if you are excluding the id in the payload that should be there in its entirety. This is where the accepted answer got it wrong. PUT must replace the entire resource, where-as patch may be partial.
One solution to this issue involves the somewhat confusing concept of "Hypertext As The Engine Of Application State," or "HATEOAS." This means that a REST response contains the available resources or actions to be performed as hyperlinks. Using this method, which was part of the original conception of REST, the unique identifiers/IDs of resources are themselves hyperlinks. So, for example, you could have something like:
GET /person/<UUID> {"person": {"location": "/person/<UUID>", "data": { "name": "Jimmy"}}}
Then, if you want to update that resource, you could do (pseudocode):
updatedPerson = person.data
updatedPerson.name = "Timmy"
PUT(URI: response.resource, data: updatedPerson)
One advantage of this is that the client doesn't have to have any idea about the server's internal representation of User IDs. The IDs could change, and even the URLs themselves could change, as long as the client has a way to discover them. For example, when getting a collection of people, you could return a response like this:
GET /people
{ "people": [
"/person/1",
"/person/2"
]
}
(You could, of course, also return the full person object for each person, depending on the needs of the application).
With this method, you think of your objects more in terms of resources and locations, and less in terms of ID. The internal representation of unique identifier is thus decoupled from your client logic. This was the original impetus behind REST: to create client-server architectures that are more loosely coupled than the RPC systems that existed before, by using the features of HTTP. For more information on HATEOAS, look at the Wikipedia article as well as this short article.
In an insert you do not need to add the id in the URL. This way if you send an ID in a PUT you may interpreted as an UPDATE to change the primary key.
INSERT:
PUT /persons/
{"id": 1, "name": "Jimmy"}
HTTP/1.1 201 Created
{"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}
GET /persons/1
HTTP/1.1 200 OK
{"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}
UPDATE
PUT /persons/1
{"id": "2", "name": "Jimmy Jr"} -
HTTP/1.1 200 OK
{"id": "2", "name": "Jimmy Jr", "other_field"="filled_by_server"}
GET /persons/2
HTTP/1.1 200 OK
{"id": "2", "name": "Jimmy Jr", "other_field"="updated_by_server"}
The JSON API uses this standard and solves some issues returning the inserted or updated object with a link to the new object. Some updates or inserts may include some business logic that will change additional fields
You will also see that you can avoid the get after the insert and update.
While it's Ok to have different representations for different operations, a general recommendation for PUT is to contain the WHOLE payload. That means that id should be there as well. Otherwise, you should use PATCH.
Having said that, I think PUT should mostly be utilised for updates and the id should always be passed in the URL as well. As a result of that, using PUT to update the resource identifier is a bad idea.
It leaves us in an undesirable situation when id in the URL can be different from the id in the body.
So, how do we resolve such a conflict? We basically have 2 options:
throw a 4XX exception
add a Warning(X-API-Warn etc) header.
That's as close as I can get to answering this question because the topic in general is a matter of opinion.
This has been asked before - the discussion is worth a look:
Should a RESTful GET response return a resource's ID?
This is one of those questions where it's easy to get bogged down into debate around what is and is not "RESTful".
For what it's worth, I try to think in terms of consistent resources and not change the design of them between methods. However, IMHO the most important thing from a usability perspective is that you are consistent across the entire API!
There is nothing bad in using different approaches. but i think the best way is the solution with 2nd.
PUT /person/UUID {"name": "Jimmy"}
GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}
it is mostly used in this way even the entity framework use this technique when the entity is added in dbContext the class without the generated ID is ID generated by reference in Entity Framework.
You may need to look into PATCH/PUT request types.
PATCH requests are used to update a resource partially whereas in PUT requests, you have to send the entire resource where it gets overridden on the server.
As far as having an ID in the url is concerned, I think you should always have it as it is a standard practice to identify a resource. Even the Stripe API works that way.
You can use a PATCH request to update a resource on the server with ID to identify it but do not update the actual ID.
I'm looking at this from a JSON-LD/ Semantic Web point of view because that's a good way to go to achieve real REST conformance as I have outlined in these slides. Looking at it from that perspective, there is no question to go for option (1.) as the ID (IRI) of a Web resource should always be equal to the URL which I can use to look-up/ dereference the resource.
I think the verification is not really hard to implement nor is it computationally intens; so I don't consider this a valid reason for going with option (2.).
I think option (3.) is not really an option as POST (create new) has a different semantics than PUT (update/ replace).