How to properly structure REST endpoints for PUT and POST - rest

I have a REST service for managing users.
HTTP GET("/users") - get all users
HTTP GET("/users/{id}") - get data for specific user
When changing something about the user I'm not sure how structure the paths for PUT/PATCH.
Option 1:
HTTP PUT ("/users") and transfer the user data (id, first name, last name) in the request body
HTTP PATCH ("/users") and transfer the user's ID and PASSWORD in the request body
Option 2:
HTTP PUT ("/users/{id}") and transfer the user data (id, first name, last name) in the request body
HTTP PATCH ("/users/{id}") and transfer the user's ID and PASSWORD in the request body
Option 3:
HTTP PUT ("/users/{id}") and transfer the user data (id, first name, last name) in the request body
HTTP PATCH ("/users/{id}/password") and transfer the user's ID and PASSWORD in the request body
#RequestMapping(value = "/users")
public interface UserController {
#GetMapping(value = "/{id}", produces = "application/json")
User getUser(#PathVariable long id);
#PutMapping(value = "", consumes = "application/json")
void addNewUser(#RequestBody User ser);
#PatchMapping(value = "/{id}/password", consumes = "application/json")
void changeUserPassword(#RequestBody UserPasswordChange passwordChangeModel, #PathVariable String id);
I'm not sure which of these approaches is the best. I can get all the data from the request body every time but I'm not sure what should be the best path to create. Using "/users/{id}" to change details about the user makes sense because I'm changing for a specific user but since I can read the ID from the request body, the path variable is redundant here.
It's the same confusion when changing the password. Since I have just one Patch endpoint under "/users" should I still use the "/users/{id}/password" or maybe I should delete the "/password" part?

When changing something about the user I'm not sure how structure the paths for PUT/PATCH.
Both PUT and PATCH are document editing requests. "Please make your representation of this resource look like mine".
In an idealized form, I would have some sort of HTTP aware document editor. I would GET a representation of the resource from you, make edits to my local copy, then send a representation of my local copy back to you.
Getting useful work done is a side effect of passing these documents around. See Jim Webber's talk.
Options 1, I think we can simply reject on first principles. If the resource identified by /users is a collection of users, then trying to replace its representation with that of a single user is not a step in a useful direction. Semantically, if you wanted to edit or insert a user by interacting with the /users resource, you would do that by either (a) making an edit to the representation of the collection, and sending the entire representation back (PUT), or by sending a description of the diff back to the server (PATCH).
Option 2, has a subtler issue -- if the password is part of the representation of the /users/id resource, then the password should also be part of the body of the PUT request. PUT and PATCH are different ways of passing our local representation of the resource back to the server; we shouldn't be thinking of them as having different information about the resource.
It's perfectly reasonable to separate the password into a different resource from the rest of the user. Unless the representation of the password resource is very large relative to the password itself, I would expect PUT rather than PATCH to be used in most cases.
So you are suggesting that option 3 would make the most sense?
Not quite - both resource designs (either with all of the information available in one resource, or with the information divided between two resources) are fine. You pick one, and then make sure the idioms you use for updating the resource(s) are appropriate.

Related

REST API Design: Path variable vs request body on UPDATE (Best practices)

When creating an UPDATE endpoint to change a resource, the ID should be set in the path variable and also in the request body.
Before updating a resource, I check if the resource exists, and if not, I would respond with 404 Not Found.
Now I ask myself which of the two information I should use and if I should check if both values are the same.
For example:
PUT /users/42
// request body
{
"id": 42,
"username": "user42"
}
You should PUT only the properties you can change into the request body and omit read-only properties. So you should check the id in the URI, because it is the only one that should exist in the message.
It is convenient to accept the "id" field in the payload. But you have to be sure it is the same as the path parameter. I solve this problem by setting the id field to the value of the path parameter (be sure to explain that in the Swagger of the API). In pseudo-code :
idParam = request.getPathParam("id");
object = request.getPayload();
object.id = idParam;
So all these calls are equivalent :
PUT /users/42 + {"id":"42", ...}
PUT /users/42 + {"id":"41", ...}
PUT /users/42 + {"id":null, ...}
PUT /users/42 + {...}
Why do you need the id both in URL and in the body? because now you have to validate that they are both the same or ignore one in any case. If it is a requirement for some reason, than pick which one is the one that is definitive and ignore the other one. If you don't have to have this strange duplication, than I'd say pass it in the body only
If you take a closer look at how HTTP works you might notice that the URI used to send a request to is also used as key for caching results. Any non-safe operation performed on that URI, such as POST, PUT, PATCH, will lead to (intermediary) caches automatically invalidating any stored responses for that URI. As such, if you use an other URI than the actual resource URI you are actually bypassing that feature and risk getting served outdated state from caches. As caching is one of the few constraints REST has simply skipping all caching via certain directives isn't ideal in first place.
In regards to including the ID of the resource or domain entity in the URI and/or in the payload: A common mistake in designing so-called REST APIs is that the domain object is mapped in a 1:1 manner onto a resource. We had a customer once who went through a merger and in a result they ended up with the same products being addressed by multiple IDs. In order to reduce the data in their DB they at one point tried to consolidate their data and continue. But they had to support still the old URIs they exposed for their products. In the end they realized that exposing the product ID via the URI wasn't ideal in their situation as it lead to plenty of downstream changes that affected their customers. As such, a recommendation here is to use UUIDs that don't give the target resource any semantic meaning and don't ever change. If the product ID in the back changes it doesn't affect the exposed URI at all. Sure, you might need a further table/collection to map from the product to the actual resource URI but you in the end designed your system with the eventuality of change which it now is more likely to coop with.
I've read so many times that the product ID shouldn't be part of the resource as it is already present in the URI. First, the whole URI is a unique identifier of that resource and not only a part of it. Next as mentioned above, IMO the product ID shouldn't be part of the URI in first place but it should be part of the resources' state. After all, the product ID is part of the products properties and therefore should be included there accordingly. As such, the media type exposed should contain all the necessities that a client is able to identify the product ID off the payload. The media type the resource's state is exchange with should also provide means to include the ID if you want to perform an update. I.e. if you take HTML as example, here you get served a HTML form by the server which basically teaches you where to send the request to, which HTTP operation to use, which media-type to marshal the request with and the actual properties of the resource, including the ones you are not meant to change. HTML does this i.e. via hidden input fields. Other form-based media types, such as HAL forms, JsonForms or Ion, might provide other mechanisms though.
So, to sum my post up:
Don't map the product ID onto URIs. Use a mapping from product ID to UUIDs instead
Use form-based media-types that support clients in creating requests. These media types should allow to include unmodifiable properties, such as hidden input fields and the like

Should API PUT endpoint receive all parameters, even if they are not editable?

There is a object of a name Car in the backend database. It contains several fields:
id
name
age
vinNumber
retailerId
There is also a API that elevates adding and editing the car:
POST /car - creates a car
PUT /car/{carId} - updates a car
User of a API can provide name, age and vinNumber while creating a car in a POST body.
When updating a car user can edit name and age. VinNumber is not enabled to be edited after creating a car.
Also retailerId is not editable since it comes from another system to the backend database.
Since that said, we have two fields that should not be edited with the API: vinNumber and retailerId.
So, taking into account REST idempotency, should the PUT request require the user of the API vinNumber and retailerId to be provided also, that were received earlier by GET request? In spite these parameters should not be editable?
An important thing to recognize -- the HTTP specification describes the semantics of an HTTP request; what does this message mean? It allows clients and servers implemented by different organizations to collaborate without requiring a direct partnership between the two.
The point being that a generic client can prepare a request for a generic server without needing out of band information.
PUT, semantically, is a request that the server change its current representation of a resource to match the client's local copy.
If "the server" was just an anemic data store (a facade in front of a file system, or a document database), then the effect of PUT at the server would just be to write the message-body as is into storage.
The point of REST, and the uniform interface, is that your server should always understand the messages the same way that the anemic facade understands them.
Similarly, your server should use the same shared semantics for its responses.
If the representations you are working with include vinNumber and retailId, then the client should be sending those fields unless the request is to remove them from the representation altogether (which may or may not be allowed, depending on whether or not they are required).
The server should understand that the request missing those fields is trying to remove them, and a request with new values in those fields is trying to change them. It can then decide what it wants to do with that request, and send the corresponding response.
Roy Fielding wrote about GET semantics in 2002:
HTTP does not attempt to require the results of a GET to be safe. What it does is require that the semantics of the operation be safe, and therefore it is a fault of the implementation, not the interface or the user of that interface, if anything happens as a result that causes loss of property (money, BTW, is considered property for the sake of this definition).
The same idea holds for PUT (and also the other HTTP methods); we hold the implementation responsible for loss of property if its handling of the request doesn't match the semantics.
According to the PUT request documentation- one should provide the complete data (ie vinNumber and retailerId also) - https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods
You could use PATCH instead for such cases.
Also what we done initally and i have see many times is POST /car/{carId}

Rest Api: When to use Post, PUT, PATCH and Delete

I am working on a restful api and I need to update a resource (i.e. a customer detail record with 10 fields).
On Add request, I send a Post request with complete record.
On update request, I send a PUT request with complete record of 10 fields.
On Verify request, I send a PUT request with just two fields i.e. recordId and versionNo.
On Delete request, I send a DELETE request with two fields in HttpOptions.
I have few questions that:
Although, it a restful api but specific application which would be used by an angular application, So should I return data in response of POST/PUT requests.
Should I use PATCH in case of Verify (or anyother action where just recordId and versionNo send to server to change some fields) or it is OK to use PUT.
To make uniformity, should I send data in body of delete request as I need recordId and versionNo to delete a record.
Should I use PATCH in case of Verify (or anyother action where just
recordId and versionNo send to server to change some fields) or it is
OK to use PUT.
In RESTful API designs, PUT requests are generally used to add or replace an entire resource, whereas a PATCH should be just used to update an existing resource. A PUT request is called "idempotent" - no matter how many times you send a PUT response, you should get the same result. A PATCH is not idempotent.
example:
PATCH /Cars/vauxhall-astra/engine --> This request would be used to only update the engine of my already existing vauxhall astra
PUT /Cars/renault-clio --> This request would create a new Renault Clio or, if it already exists, replace the entire Clio using the data specified in my request. A Clio would then be guaranteed to exist after my request is successful, regardless of whether it existed or not before.
Although, it a restful api but specific application which would be used by an angular application, So should I return data in response of POST/PUT requests.
Totally up to you, returning data from a POST/PUT is fine - especially if it saves you having to make extra GET api requests. Just always make sure you are only ever returning the data you need from a response.
To make uniformity, should I send data in body of delete request as I need recordId and versionNo to delete a record.
Again it's totally up to you. Whether you use query parameters (e.g. DELETE cars?id=123) or a request body is just your preference, there's nothing in REST that has rules for this.
REST Response
A RESTful API MUST always answer with HTTP codes to client requests:
Success and error responses are a vital part to define how an API is used correctly.
Refer to this guide to solve all your RESTful related questions.
PATCH/PUT
From Wikipedia:
The main difference between the PUT and PATCH method is that the PUT method uses the request URI to supply a modified version of the requested resource which replaces the original version of the resource whereas the PATCH method supplies a set of instructions to modify the resource. If the PATCH document is larger than the size of the new version of the resource sent by the PUT method then the PUT method is preferred.
Also:
Using the PUT method consumes more bandwidth as compared to the PATCH method when only a few changes need to be applied to a resource. But when the PATCH method is used, it usually involves fetching the resource from the server, comparing the original and new files, creating and sending a diff file. On the server side, the server has to read the diff file and make the modifications. This involves a lot of overhead compared to the PUT method.[11] On the other hand, the PUT method requires a GET to be performed before the PUT and it is difficult to ensure that the resource is not modified between the GET and PUT requests.
So I will use PATCH for verifying a resource.
DELETE
Normaly, for DELETE requests, the client specifies the id of the resource and pass it ass a Path Variable on the URL:
curl -X DELETE http://example.com/resource/{id}
But you can pass a body on the request also. This possibility is stated by MDN Mozilla Web DOCS:
Request has body - May
Successful response has body - May
Even though others have answered the question in details before me but still I'm posting this just to provide a handy short difference between all of these HTTP methods
1.HTTP Post:It is used to create an item
2.HTTP Put:It is used to update an item
3.HTTP Patch:It is used to partially update an item
4.HTTP Delete:It is used to delete an item

Updating a resource through REST (PUT/POST)

When updating a resource via REST, should one include in the body just the values to update, or the whole object (current values and values to update)?
If a User object looks like this
User (id, name, age, sex)
and I want to update only his name and age, should my request look like this:
PUT /users/1
{"name":"john","age":18}
or like this:
PUT /users/1
{"name":"john","age":18, "sex":"m"}
And what should that look like on the server side?
#RequestMapping(value = "/{userId}", method = PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> updateUser(#PathVariable final int userId, #RequestBody User u){
//fetch user by ID
user.setName(u.getName())
user.setAge(u.getAge())
user.setSex(u.getSex()) //this will be empty?
return new ResponseEntity<String>(gson.toJson(user), HttpStatus.OK);
}
Or alternatively I could find out which variables were not included in the request body and do something like this
if(u.getName()!=null){
user.setName(u.getName())
}
if(u.getAge()!=null){
user.setAge(u.getAge())
}
if(u.getSex()!=null){
user.setSex(u.getSex())
}
Is there a right/wrong way to achieve this, or is it a case of just doing what's easiest?
PUT requests must be idempotent and should provide as its payload a complete representation of the entity it is replacing. (https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4)
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.
A partial JSON object PUT request would be a PATCH with Content-Type: application/merge-patch+json (https://www.rfc-editor.org/rfc/rfc7396)
Things to think about. You might have multiple clients updating an entity at the same time, using a PUT could end up overwriting changes other clients have made.
In that case you might want to set a pre-condition to check if the object was updated between the time that the requesting client fetched the entity, made changes and submitted the PUT/PATCH request. For example the pre-condition could be a last updated timestamp, hash (Etag) or a version number; Or you could use a "last write wins" approach which is common in eventually consistent systems. It all depends on your system and the situation.
On the server side, if you support partial updates then as you have provided in your example, you would identify the set of properties included in the request and only set the specific ones that were provided.

Rest API: path for accessing derived data

It is not clear to me that if I have a micro service that is in place to provide some derived data how the rest api should be designed for this. For instance :-
If I have a customer and I want to access the customer I would define the API as:
/customer/1234
this would return everything we know about the customer
however if I want to provide a microservice that simply tells me if the customer was previously known to the system with another account number what do I do. I want this logic to be in the microservice but how do I define the API
customer/1234/previouslyKnow
customerPreviouslyKnown/1234
Both don't seem correct. In the first case it implies
customer/1234
could be used to get all the customer information but the microservice doesn't offer this.
Confused!
Adding some extra details for clarification.
I suppose my issue is, I don't really want a massive service which handles everything customer related. It would be better if there were lighter weight services that handles customer orders, customer info, customer history, customer status (live, lost, dead....).
It strikes me all of these would start with
/customer/XXXX
so would all the services be expected to provide a customer object back if only customer/XXXX was given with no extra in the path such as /orders
Also some of the data as mentioned isn't actually persisted anywhere it is derived and I want the logic of this hidden in a service and not in the calling code. So how is this requested and returned.
Doing microservices doesn't mean to have a separate artifact for each method. The rules of coupling and cohesion also apply to the microservices world. So if you can query several data all related to a customer, the related resources should probably belong to the same service.
So your resource would be /customers/{id}/previous-customer-numbers whereas /customers (plural!) is the list of customers, /customers/{id} is a single customer and /customers/{id}/previous-customer-numbers the list of customer numbers the customer previously had.
Try to think in resources, not operations. So returning the list of previously used customer numbers is better than returning just a boolean value. /customer/{id}/previous-accounts would be even better, I think...
Back to topic: If the value of previous-accounts is directly derived from the same data, i.e. you don't need to query a second database, etc. I would even recommend just adding the value to the customer representation:
{
"id": "1234",
"firstName": "John",
"lastName": "Doe",
"previouslyKnown": true,
"previousAccounts": [
{
"id": "987",
...
}
]
}
Whether the data is stored or derived shouldn't matter so the service client to it should not be visible on the boundary.
Adding another resource or even another service is unnecessary complexity and complexity kills you in the long run.
You mention other examples:
customer orders, customer info, customer history, customer status (live, lost, dead....)
Orders is clearly different from customer data so it should reside in a separate service. An order typically also has an order id which is globally unique. So there is the resource /orders/{orderId}. Retrieving orders by customer id is also possible:
/orders;customer={customerId}
which reads give me the list of orders for which the customer is identified by the given customer id.
These parameters which filter a list-like rest resource are called matrix parameters. You can also use a query parameter: /orders?customer={customerId} This is also quite common but a matrix parameter has the advantage that it clearly belongs to a specific part of the URL. Consider the following:
/orders;customer=1234/notifications
This would return the list of notifications belonging to the orders of the customer with the id 1234.
With a query parameter it would look like this:
/orders/notifications?customer=1234
It is not clear from the URL that the orders are filtered and not the notifications.
The drawback is that framework support for matrix parameters is varying. Some support them, some don't.
I'd like matrix parameters best here but a query parameter is OK, too.
Going back to your list:
customer orders, customer info, customer history, customer status (live, lost, dead....)
Customer info and customer status most likely belong to the same service (customer core data or the like) or even the same resource. Customer history can also go there. I would place it there as long as there isn't a reason to think of it separately. Maybe customer history is such a complicated domain (and it surely can be) that it's worth a separate service: /customer-history/{id} or maybe just /customer/{id}.
It's no problem that different services use the same paths for providing different information about one customer. They are different services and they have different endpoints so there is no collision whatsoever. Ideally you even have a DNS alias pointing to the corresponding service:
https://customer-core-data.service.lan/customers/1234
https://customer-history.service.lan/customers/1234
I'm not sure if I really understand your question. However, let me show how you can check if a certain resource exist in your server.
Consider the server provides a URL that locates a certain resource (in this situation, the URL locates a customer with the identifier 1): http://example.org/api/customers/1.
When a client perform a GET request to this URL, the client can expect the following results (there may be other situation, like authentication/authorization problems, but let's keep it simple):
If a customer with the identifier 1 exists, the client is supposed to receive a response with the status code 200 and a representation of the resource (for example, a JSON or XML representing the customer) in the response payload.
If the customer with the identifier 1 do not exist, the client is supposed to receive a response with the status code 404.
To check whether a resource exists or not, the client doesn't need the resource representation (the JSON or XML that represents the customer). What's relevant here is the status code: 200 when the resource exists and 404 when the resource do not exist. Besides GET requests, the URL that locates a customer (http://example.org/api/customers/1) could also handle HEAD requests. The HEAD method is identical to the GET method, but the server won't send the resource representation in HEAD requests. Hence, it's useful to check whether a resource exists or not.
See more details regarding the HEAD method:
4.3.2. HEAD
The HEAD method is identical to GET except that the server MUST NOT
send a message body in the response (i.e., the response terminates at
the end of the header section). The server SHOULD send the same
header fields in response to a HEAD request as it would have sent if
the request had been a GET, except that the payload header fields MAY be omitted. This method can be used for obtaining
metadata about the selected representation without transferring the
representation data and is often used for testing hypertext links for
validity, accessibility, and recent modification. [...]
If the difference between resource and resource representation is not clear, please check this answer.
One thing I want to add to the already great answers is: URLS design doesn't really matter that much if you do REST correctly.
One of the important tenets of REST is that urls are discovered. A client that has the customers's information already, and wants to find out what the "previously known" information, should just be able to discover that url on the main customer resource. If it links from there to the "previously known" information, it doesn't matter if the url is on a different domain, path, or even protocol.
So if you application naturally makes more sense if "previouslyKnown" is on a separate base path, then maybe you should just go for that.