Reputation: 3440
I have looked at this PUT vs POST question and others on stackoverflow and after going through the answers I found out:
Use POST if server identifies the address of the resource
Use PUT if client know the address of the resource.
Now above works fine if I have a single independent entity. For example if I have Student entity I am admitting a new student to schools I might create a REST endpoint as /api/schools/schools-name/student
with POST
HTTP method. But once the student has been admitted and I have to make changes to this student I can use Patch/PUT.
But In my case I have dependent entities that is parent and child. First I create parent entity using the POST. Now the child entity is created only after parent entity has been created. Why they can't be created together like after parent entity is created, create the child entity also, is because of business requirement.
Important points to note are that parent and child entity are linked by an id column only. So currently my url for creating child entity is /api/entities/parent-entity-id
. Also there is no request body while creating the child entity as all the required info for creating is stored in parent entity.
My question is that should this method be POST as we are creating the child entity or PUT as I am updating the children of the parent entity which already has been created?
Upvotes: 0
Views: 3422
Reputation: 12839
First and foremost, REST is an architecture style used if you need decoupling of clients from servers to allow evolving the server side without risking clients to break. REST isn't a toolset you pick the most suitable things out and leave out the remainder. It is more of an either apply all of the steps and constraints REST proposes or you wont benefit from it thing! For simple back- to frontend communication it is probably to much effort as you are usually in control of both ends, however, if you aren't in control of one end only then you might gain the most benefit of such a design actually.
REST relies heavily on standardized protocols and media types. The interaction model is very similar to the browsable Web, the big cousin of REST. Therefore, the same concepts that apply to the Web also apply to REST. The core idea in both should always be that the server teaches the client on how to do things while clients only take what they are given without trying to deduce further knowledge from either previous interaction or analysis of URIs or the like. I.e. on the Web, HTML forms are used to allow clients to enter certain input that is sent to the server upon clicking a submit button. Both the target URI as well as the method to use are included in that Web form so a client actually doesn't have to care about that fact. Through the affordance of the button element, a client also has the implicit knowledge that a button can be clicked and certain actions may be triggered as a consequence. The same concepts used in the Web should now be used between applications to interact with each other. Here, either HTML forms can be reused or certain, specialized media-types need to be developed (i.e. like hal-forms). Through content-type negotiation client and server can actually agree on a representation format both support and therefore avoid interoperability issues.
One common issue many "REST developer" seem to have is to think of REST endpoints returning certain data to be of certain types, i.e. the data of a company employee or the items of a certain hierarchies. Fielding claims that instead of introducing typed resources meaningful to a client, REST APIs should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and defining application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types.
A further thing to mentioned here, which I already striped a bit in my comment, is that URIs don't inherit a parent-child relationship by default. A URI as a whole, including any path, matrix and/or query parameters is just a link to a resource and can be considered as a key used for caches to return a response body previously stored for that key (=URI). Clients therefore shouldn't attempt to deduce semantic knowledge from URIs itself but just use the link relations returned for such URIs. This allows servers to replace URIs down the road while clients still can invoke them based on the name the URI was returned for.
As URIs themselves don't convey any semantic information, they can't really express a parent-child relationship on their own. We humans tend to interpret a URI such as /api/company/abc/employee/123
as expressing that employee with the number 123
is working for company abc
, which might be true, but also does not have to be as explained before, URIs lack the semantic of expressing such things. It is only through the utilization of a bunch of such URIs that such a semantic tree can be created.
But In my case I have dependent entities that is parent and child. First I create parent entity using the POST. Now the child entity is created only after parent entity has been created.
If you take a closer look at the HTTP methods you might see that POST requests are processed according to the resource's own specific semantics, meaning that you literally can perform anything you have to here. This is defacto a swiss-army-knife in your toolset available and should be used if the other methods aren't fitting your use-case.
PUT i.e. is specified to replace the current targets representation with the one provided in the payload of the request. However, a server is allowed to validate whether the PUT
representation is consistent with any constraints the server has for the target resource and may reject therefore requests to update a certain resource due to conflicts with certain constraints. PUT
is further allowed to reconfigure a targets media-type to match a more suitable representation, apply a transformation onto the received payload to convert the payload to a matching one of the target resource or reject the payload in general.
Neither HTTP methods nor URIs can create such a semantic relationship between a parent and child resources. However, this is what link relations are there for! Links are edges between two entities that give a name to the context of the relation between those two entities. Such link relations should be standardized, follow common conventions or represent extension types as defined in RFC 5988 (Web linking) to promote their reusage. Unfortunately, however, IANA does not directly specify a parent
and child
link relation. up
may be used to refer from a child to a parent, in a tree. Through an extension mechanism this is however relatively easy to obtain, i.e. http://api.acme.com/rel/parent
and http://api.acme.com/rel/child
or something similar.
The next bit to discuss on the quoted segment of the initial post would be happens-before semantics of the creation of the parent in contrast to the child resource. HTTP does not have any kind of transaction semantics nor guarantees of ordering of requests other than outlined in the pipelining section, which only applies to safe methods anyways. HTTP therefore does not give any promises to the processing of requests as they either might not reach the server at all or the response just got lost for whatever reason. Only if the client is receiving a 201 Created
response including a Location
header pointing to the created resource a client knows for sure that a resource got created and according to the specification only then a client is allowed to create a further child resource.
To a generic HTTP server both the creation request of the parent as well as the consecutive request of creating the child resource are two distinctive requests which it will attempt to fulfill independently. This is the stateless nature of HTTP. As mentioned before though, certain validation of resource's own constraints might be performed preventing the creation of children though.
Important points to note are that parent and child entity are linked by an id column only. So currently my url for creating child entity is /api/entities/parent-entity-id. Also there is no request body while creating the child entity as all the required info for creating is stored in parent entity.
REST doesn't care about your domain model actually. What you have here is a classical example of /persons
resources, where three persons are identifiable via separate, distinctive URIs such as /persons/alice
, /persons/bob
and /persons/joe
. We don't know anything about the actual data returned by any of these endpoints actually and by itself, as above mentioned, you can't deduce from the URI directly whose parent of whom (or that any of the URIs actually represents a person to start with). Through link-relation such a context structure can now be given, stating that Bob and Alice are parents of Joe and Joe is a child of both Bob and Alice.
Note how in the example above the actual content of the resources was not of importance to the client. We still don't know if either of the resources contain any information at all. All we know is that there are 3 resources available that are linked to each other in some way. So if the intent of your system is to just represent such relationships than go ahead. Use links between those resources to allow clients to lookup these relationships if interested. If a client is interested in the details of a resource it will send a request for a certain set of media-types to the server anyways. Discoverability and exploration are two common things you will want to guarantee in a REST ecosystem.
My question is that should this method be POST as we are creating the child entity or PUT as I am updating the children of the parent entity which already has been created?
AS POST
is an all-purpose tool that has to be used if the other methods aren't fitting, using POST
is for sure not wrong. If you take a closer look on the other methods you might see that they serve different purposes, i.e. PUT
has the semantics of replacing the current content with the one given in the request payload. It therefore expresses a different use-case than you actually want IMO. As such you should stick to POST
also for generating your children.
What you should do within your POST
logic, as hopefully was clear enough throughout this answer, is to introduce meaningful link-relations that give the relations between the "entities" some context you can name. Such an operation can further have side effects which allows you to update the parent resource as well and introduce some further links that point from the parent back to the child.
This post is probably already way longer than it needs to be, though I want to make sure that you understand the intent behind REST and when to use it. Unless you really need a system that requires properties such as freedom for evolution, failure robustness and support for the operation of the application/system for decades to come, either exposing your own RPC service or maybe exposing your data model directly is probably easier to obtain.
Upvotes: 1
Reputation: 57277
As mentioned in the question there is no request body for creating a child entity. This api is just to trigger the child entity creation. Parent entity already has all the info.
If you are sending an unsafe request to the server, and it doesn't match the semantics of any of the other HTTP methods, then you should use POST.
In particular, if the message-body is not a candidate representation for the resource identified by the target-uri, then PUT is out of bounds.
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
Upvotes: 1
Reputation: 500
You are creating a new instance, so you should use POST method on endpoint for previously created parent instance. Example:
POST /parent/<parent_id>/children/
BODY:
{"json with children data...."}
Upvotes: 0
Reputation: 151604
Also there is no request body while creating the child entity as all the required info for creating is stored in parent entity.
So, this has nothing to do with resource state and therefore nothing to do with REST.
You're not PUTting a new state of a resource, so you should stay away from using PUT.
Upvotes: 0