Handling CRUD on child objects with RESTful
If given the following xml request sent to a RESTful API endpoint called /catalog via a PUT (Intent to update catalog).
If the user provides additional <book>
s that don't exist at that point in the catalog in the request should the endpoint "Create" them? or should they be ignored and a different endpoint perhaps /books be used to create them.
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
<book id="bk103">
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
<description>After the collapse of a nanotechnology
society in England, the young survivors lay the
foundation for a new society.</description>
</book>
<book id="bk104">
<author>Corets, Eva</author>
<title>Oberon's Legacy</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2001-03-10</publish_date>
<description>In post-apocalypse England, the mysterious
agent known only as Oberon helps to create a new life
for the inhabitants of London. Sequel to Maeve
Ascendant.</description>
</book>
<book id="bk105">
<author>Corets, Eva</author>
<title>The Sundered Grail</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2001-09-10</publish_date>
<description>The two daughters of Maeve, half-sisters,
battle one another for control of England. Sequel to
Oberon's Legacy.</description>
</book>
<book id="bk106">
<author>Randall, Cynthia</author>
<title>Lover Birds</title>
<genre>Romance</genre>
<price>4.95</price>
<publish_date>2000-09-02</publish_date>
<description>When Carla meets Paul at an ornithology
conference, tempers fly as feathers get ruffled.</description>
</book>
<book id="bk107">
<author>Thurman, Paula</author>
<title>Splish Splash</title>
<genre>Romance</genre>
<price>4.95</price>
<publish_date>2000-11-02</publish_date>
<description>A deep sea diver finds true love twenty
thousand leagues beneath the sea.</description>
</book>
<book id="bk108">
<author>Knorr, Stefan</author>
<title>Creepy Crawlies</title>
<genre>Horror</genre>
<price>4.95</price>
<publish_date>2000-12-06</publish_date>
<description>An anthology of horror stories about roaches,
centipedes, scorpions and other insects.</description>
</book>
<book id="bk109">
<author>Kress, Peter</author>
<title>Paradox Lost</title>
<genre>Science Fiction</genre>
<price>6.95</price>
<publish_date>2000-11-02</publish_date>
<description>After an inadvertant trip through a Heisenberg
Uncertainty Device, James Salway discovers the problems
of being quantum.</description>
</book>
<book id="bk110">
<author>O'Brien, Tim</author>
<title>Microsoft .NET: The Programming Bible</title>
<genre>Computer</genre>
<price>36.95</price>
<publish_date>2000-12-09</publish_date>
<description>Microsoft's .NET initiative is explored in
detail in this deep programmer's reference.</description>
</book>
<book id="bk111">
<author>O'Brien, Tim</author>
<title>MSXML3: A Comprehensive Guide</title>
<genre>Computer</genre>
<price>36.95</price>
<publish_date>2000-12-01</publish_date>
<description>The Microsoft MSXML3 parser is covered in
detail, with attention to XML DOM interfaces, XSLT processing,
SAX and more.</description>
</book>
<book id="bk112">
<author>Galos, Mike</author>
<title>Visual Studio 7: A Comprehensive Guide</title>
<genre>Computer</genre>
<price>49.95</price>
<publish_date>2001-04-16</publish_date>
<description>Microsoft Visual Studio 7 is explored in depth,
looking at how Visual Basic, Visual C++, C#, and ASP+ are
integrated into a comprehensive development
environment.</description>
</book>
</catalog>
I am finding a lot on SO that talks about PUT vs POST and best practices for doing CRUD operations on a root object but I've spent the night trying to find information around how child objects should be handled.
According to http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html it isn't clear to me if this applies to child objects?
9.6 PUT
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI. If a new resource is created, the origin server MUST inform the user agent via the 201 (Created) response. 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 resource could not be created or modified with the Request-URI, an appropriate error response SHOULD be given that reflects the nature of the problem. The recipient of the entity MUST NOT ignore any Content-* (eg Content-Range) headers that it does not understand or implement and MUST return a 501 (Not Implemented) response in such cases.
From my understanding of REST, books are resources and should be handled through their own endpoint and an update to the catalog should only be used to add existing books to a catalog, not create them.
So in this scenario a book that does not exist would be ignored/not added to the catalog until a create request is submitted to create the book.
This would mean the user would send a POST /book to create the book, followed by a PUT to /catalog with the book in the request to add it to the catalog.
You're right. You have two different resources here. One is named Books and the other is named Catalogs. You must design two different URIs to address each one. So in this scenario, I'd create two different resources to handle this problem. The first resource would be named as /catalogs and you must build it to receive only the book ID (one or more) that someone wants to associate with this catalog. You'll have:
Endpoint -> https://yourapi.com/catalogs
POST to https://yourapi.com/catalogs --> creates a new catalog.
PUT to https://yourapi.com/catalogs/1 --> updates the catalog with ID = 1.
PUT to https://yourapi.com/catalogs/2 where id 2 doesn't exist --> creates a new catalog with id=2
You have to send the XML below to the endpoint pointed above.
<?xml version="1.0"?>
<catalog>
<book id="bk101"/>
<book id="bk102"/>
<book id="bk103"/>
<book id="bk104"/>
<catalog>
The second resource should be /books and you must use it to create, delete, update and list books. Once you've created a book, then you can associate it with a catalog. You shouldn't use the resource Catalogs to create a Book that way. To my mind, it doesn't make sense.
What you are trying to do is a bulk/batch update. Afaik. we don't have consensus how to do that. There are many issues here:
/catalog
(so every single book in your storage) here, you have to give a representation of the whole catalog. You should consider PATCH instead, which can be used for partial update. You can find a description about PATCH here: PATCH Method for HTTP.
With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version. The PATCH method affects the resource identified by the Request-URI, and it also MAY have side effects on other resources; ie, new resources may be created, or existing ones modified, by the application of a PATCH.
So PATCH /catalog
and your XML would be okay. You can decide whether you allow your users to give the id of the new resources, or you can generate it on server side.
Ofc. you have alternatives, for example you can send a book collection with POST /catalog
, so multiple book resources will be created. You can use PUT /catalog/?id="bk112,bk113,..."
to update a specific collection of books. Another alternative to create everything one by one, as you already mentioned.
Be aware that we are talking about hyperlinks ( METHOD /resource-id?query <data />
+ link metadata: eg link relation
). So you should consider to add links to your resource representations you return by a GET and probably use a hypermedia format as well eg HAL+XML or ATOM+XML.
下一篇: 使用RESTful处理子对象上的CRUD