I'm using Gatling for performance testing.
My scenario includes creating nested resources. E.g.
1. Create Parent
1.1. ---- Create Child_1
1.2. ---- create Child_2
1.2.1 ---- ---- Create Grand-child_2_1
etc.
Constraint: you can't delete a parent resource if it has children.
As a consequence, I have to delete resources in reverse order.
One way to achieve this, is to save created resources in session list, and delete items at the end.
But I'm not satisfied with this approach, as it requires developers to add hooks of API locations and created resources' names, etc..
I'd like to know if there is an option to rely on log file to retrieve all POST requests, and dynamically delete them.
Limitations of the 2nd approach:
POST API is slightly different than DELETE API:
POST /books (with some payload) vs. DELETE /books/{id}
so, I may have to look at GET requests in the log (which are similar to DELETE)
I'm not sure if the *.log file is available while the simulation is executing! If not, I can't do this as part of the execution, and may need another dedicated simulation to do the deletion.
any advice?
Related
We are designing WebAPI for our software for managing ecommerce product information. We want to provide (among many others) two operations:
Simple one: allow user to add/modify existing product information:
don't create new product if it not exists
don't delete any information from existing product which was not provided in this request
In my opinion HTTP PATCH method is proper way to handle this scenario (with json-patch or json-merge-ptach) with URL like this: /products/{ID}
Harder one: allow user to add/modify existing product or create one
create product if not exists in DB
don't delete any information from existing product which was not provided in this request (same behaviour as in first case)
I'm struggling with designing REST endpoint for this second use case. I have few options but none of them fits perfectly for me in the REST principles:
a) Add custom HTTP header to the endpoint designed for first case (patch) to allow a caller to control of "not found behaviour" eg. create-entity-when-not-exists: true/false - but in my opinion PATCH shouldn't be used for creating resources.
b) Design new endpoint using PUT with special header "preserve-not-provided-data" - this on the other hand violates for me PUT principles because PUT is create-or-replace not create-or-update method
c) Create PATCH for /products URL (without {ID} at the end) - in this case we are updating whole collection(resource) of products - so if product exists we can update it or create new one if not exists.
For now c) solution looks fine for me with one exception: If in the future we would like to support batch operations (for both use cases: 1 and 2) we would like to use /products URL and it will conflict with URL from solution c)
What do you think ? Do you have any other ideas ?
PUT and PATCH have differing message semantics, but the core context ("remote authoring") is the same. In both cases, the client request is "Please, server, make your representation of this resource match my local copy".
For example, I GET a JSON document from the server. I make local edits to it. Now I want to "save" my changes on the server. If the document is modest in size, I might just send the entire revised document over the network. If the document is very large, and my changes are modest, then I might instead send the patch instead.
If you imagine using HTTP to publish edits of HTML web pages to a server, then you've got the right frame of reference. There's not a lot of practical difference between "please patch the title of your copy of the document" and "here is a complete new copy of the document, with my edit to the title". The bytes on disk are going to be the same in either case.
Given that, it would be very odd if those two methods for publishing a new revision of the document were to have vastly different side effects.
Your third approach, based on modifying /products, is potentially fine for both your individual and batch. The server gets the new representation of /products (or the patch document describing the changes), decides whether to accept the changes, and if so computes what it needs to do to its own database to make things work.
Note:
A PUT request applied to the target resource can have side effects on other resources.
The HTTP specification is relatively strict about what the message means, but offers the server a lot of leeway in how it behaves in response.
Let assume that I have a collection with /playrequests endpoint. It is a collection (list) for those players who want to find another player to start a match.
The server will check this collection periodically and if it finds two unassigned players, it will create another resource in another collection with /quickmatchs endpoint and also change (for example) a field in the PlayRequests collection for both players to shows that they are assigned to a quickMatch.
At this point, players can send a PUT or PATCH request to set the (for example) "ready" field of their related quickMach resource to true. so the server and each of them can find out that if both of them is ready and the match can be started.
(The Issue Part Is Below Part...)
Also, before a the playRequests assigned to a match and also after they assigned to it, they can send a DELETE request to /playrequests endpoint to tell the server that they want to give up the request. So if the match doesn't create yet, It is ok. the resource related to the player will remove from playRequests collection. but if player assigned to a match, the server must delete the related playRequest and also it must delete the related quickMatch resource from the quickMatchs collection. ( and also we should modify the playRequest related to another player to indicate that it's unassigned now. or we can check and change it later when he to check the status of his related resources in both collection. It is not the main issue for now. )
So, my question is that is it ok to change a resource that is related to the given end point and also change another resource accordingly, If it is necessary? ( I mean is it ok to manipulate different resources with different endpoints in one request? I don't want to send multiple requests.) or I need to mix those two collections to avoid such an action?
I know that many things ( different strategies ) are possible but I want to know that (from the viewpoint of RESTFUL) what is standard/appropriate and what is not? (consider that I am kinda new to restful)
it ok to change a resource that is related to the given end point and also change another resource accordingly
Yes, and there are consequences.
Suppose we have two resources, /fizz and /buzz, and the representations of those resources are related via some implementation details on the server. On the client, we have accessed both of these resources, so we have cached copies of each of them.
The potential issue here is that the server changes the representations of these resources together, but as far as the client is concerned, they are separate.
For instance, if the client sends an unsafe request to change /fizz, a successful response message from the server will invalidate the locally cached copy of that representation, but the stale representation of /buzz does not get evicted. In effect, the client now has a view of the world with version 0 /buzz and version 1 /fizz.
Is that OK? "It depends" -- will expensive things happen to you if your clients are in a state of unmatched representations? Can you patch over the "problem" in other ways (for instance, by telling the client to check resources for updates more often)?
We have website like pluralsight where authors and customers register. Authors publish their courses and customers can give rating to these courses. The table structure looks like:
author table: (save basic information of author: one to one)
authorId | name | contact | email | rating
1 | sahil | 9971343992 | shaf#gmail.com | 3.2
authorRating: (save ratings given to author from customers: one to many)
Id | authorId | customerId | rating |
1 | 1 | 101 | 2.7
2 | 1 | 201 | 3.7
The rating in the author table gets updated when some record gets inserted/updated/deleted in authorRating table. There's some complex algorithm which finalize rating in author table based on authorRating table records.
We have created following APIs for that:
PUT api/author/1/rating /: If there's any change in authorRating table, we recompute the rating of that author and trigger this API to pass new rating. This accepts rating and add/update that in author table. If author table doesn't have id=1, it gives back validation error
DELETE api/author/1/rating /: This removes the rating for author id=1 i.e. set it to NULL. If author table doesn't have id=1, it gives back validation error.
Is this the right API design? OR should we only have PUT API exposed and if they send rating as null in the PUT API, we will set it null in the author table ?
OR should we consider using PATCH here?
As far as you are modifying only a field of one structure, I think PATCH fits better here, but it should be sent to the parent resource:
PATCH api/author/1
For these rating operations, I would use something like:
To insert a new rating for author 1, use POST /api/author/1/rating
To update a rating for author 1, use PATCH /api/author/1/rating. You may want to have more data in the authorRating table that don't want to change (like author and customer ids) but you are only updating some fields, in this case, the rating.
To delete author's 1 rating, DELETE /api/author/1/rating, as you explained, makes sense.
It is a common practice to use POST method for RESTful APIs. You can post virtually any message and handle the message by the parameters. You can POST a delete, or update or other command, depending on your needs.
HTTP is a protocol which defines methods that allow to manipulate resources; files or data on the internet so to say. Any business logic triggered by one of the operations invoked are more or less just side effects while manipulating these resources. While certain things can be achived in multiple ways, operations (slightly) differ in their semantics they convey.
PUT as specified in RFC 7231, which replaces the current representation with the one provided in the request, does state the following about partial updates:
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).
So, you have either the option of "overlapping" resources and update the other resource, which has the effect of also changing the overlapping data and thus the data in the actual resource as well, or use PATCH therefore.
The primer one can easily be thought of that certain information of an other resource is embedded in the actual resource and on updating the other resource the state of the actual resource will also change as a consequence. Think of a user and his address i.e.
According to Roy Fielding, who wrote the following in his dissertation
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.”
resources should be named and referenced via own, unique identifiers. A direct mapping of entities to resources though is often not desirable as the resource can and probably should contain more information for the client to take further actions.
It is therefore up to you if you consider a rating to be a good entity and/or a good resource. I'm not a big fan of this though, though this is an opinionated position.
DELETE has some special semantics. It actually does not guarantee the removal of a file, though it will make the resource unavailable by removing the association (the URI) for that particular resource. What happens to the deleted resource is actually up to the implementation.
The DELETE method requests that the origin server remove the association between the target resource and its current functionality. In effect, this method is similar to the rm command in UNIX: it expresses a deletion operation on the URI mapping of the origin server rather than an expectation that the previously associated information be deleted.
...
If the target resource has one or more current representations, they might or might not be destroyed by the origin server, and the associated storage might or might not be reclaimed, depending entirely on the nature of the resource and its implementation by the origin server (which are beyond the scope of this specification). ... In general, it is assumed that the origin server will only allow DELETE on resources for which it has a prescribed mechanism for accomplishing the deletion.
Usually DELETE should only be used on resources that where created via PUT or POST previously whose creation was confirmed via an own Location response header.
With that being said, as you aked for whether this is the right API design or not. Actually, there is no right or wrong and which stance you take is primarily an opinionated one. As long as you stay in bounds with the HTTP protocol specification (in your particular case) you don't violate REST architect principles. If you design your rating resources in a way that make them uniquely identifiable you can use delete to unreference the respective rating from the author (and probably delete the data from your DB) or send a put request with the new content of that rating resource to the respective endpoint.
Keep in mind though, that the server should do its best to teach the client what next actions it can take without having the client to have some out-of-band information about your API, otherwise you will couple the client to your API and therefore might cause problems when you change your API in the future.
I'm working on a REST-like API.
This API have a this for changing a existing resource by ID:
/api/v1/admin/member/:ID
I any normal circumstances this would of course be a PUT when changing a resource.
But because of a compromise leading to simpler code, this route actually first delete the resource completely (and all references to it) and then create a new one based on the input given by a form.
In all means this will look and give the same end result as a resource change.
Question: Should this route be a PUT or a POST
The expected behavior is idempotent so I would say use PUT, and I would make sure the update occurs in a transaction so an error between deleting and inserting would not leave the resource deleted.
We are building a REST API with the following resources: Users, UserGroups. Currently we are supporting the following URI's:
/BASEAPI/VERSION/Users/
/BASEAPI/VERSION/Users/{id}/UserGroups
/BASEAPI/VERSION/UserGroups/
/BASEAPI/VERSION/UserGroups/{id}/Users
I like this better than including references in the objects which then have to be pulled on subsequent requests. It also means that we can avoid query params to filter the results. i.e. we don't have to support:
/BASEAPI/VERSION/UserGroups/{id}?user_id={user_id}
The problem is that it doesn't make creation and deletion semantics very clear. i.e. should a DELETE request to:
/BASEAPI/VERSION/Users/{id}/UserGroups/{group_id}
remove the UserGroup, or remove the user from the user group?
We've considered adding:
/BASEAPI/VERSION/UserGroupUsers
But something doesn't quite feel right about that, but maybe it's the best way to go. What do others think are best practices?
You need to figure out how you intend to represent the membership relationship between user and user group. It can be an attribute of the user, an attribute of the group, or a separate resource. Those are the only choices. How users are added to and removed from groups falls out naturally from your choice. Membership management becomes a PUT/DELETE to the user, the group, or the membership resource.
Personally, I find the separate resource to be the cleanest way to handle the issue, but you then need query parameters to poll for a specific user or group. Also, you'd need to change your second-level resource names, because it makes no sense for /userGroups/{id}/users to return a collection of userGroupUsers resources.
A URL addresses a resource. A GET on this URL returns the resource and a DELETE deletes it. If the DELETE would delete something different than the GET is returning something really is broken.
So if /BASEAPI/VERSION/Users/4711/UserGroups would return the UserGroups with the ID 0815 and 0816 the DELETE should delete both userGroups.
Question is: Does this make sense? What is happening to the other users in both userGroups?
If you want to remove a user from a group I would provide a PATCH Method.