Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

api - REST Complex/Composite/Nested Resources


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

@ray, excellent discussion

@jgerman, don't forget that just because it's REST, doesn't mean resources have to be set in stone from POST.

What you choose to include in any given representation of a resource is up to you.

Your case of the the covers referenced separately is merely the creation of a parent resource (comic book) whose child resources (covers) may be cross-referenced. For example, you might also wish to provide references to authors, publishers , characters, or categories separately. You may wish to create these resources separately or before the comic book which references them as child resources. Alternatively, you may wish to create new child resources upon creation of the parent resource.

Your specific case of the covers is slightly more complex in that a cover really does require a comic book, and visa versa.

However, if you consider an email message as a resource, and the from address as a child resource, you can obviously still reference the from address separately. For example, get all from addresses. Or, create a new message with a previous from address. If email was REST, you could easily see that many cross-referenced resources could be available: /received-messages, /draft-messages, /from-addresses, /to-addresses, /addresses, /subjects, /attachments, /folders, /tags, /categories, /labels, et al.

This tutorial provides a great example of cross-referenced resources. http://www.peej.co.uk/articles/restfully-delicious.html

This is the most common pattern for automatically-generated data. For example, you don't post a URI, ID, or creation date for the new resource, as these are generated by the server. And yet, you can retrieve the URI, ID, or creation date when you get the new resource back.

An example in your case of binary data. For example, you want to post binary data as child resources. When you get the parent resource you can represent those child resources as the same binary data, or as URIs which represent the binary data.

Forms & parameters are already different than the HTML representations of the resources. Posting a binary/file parameter which results in a URL isn't a stretch.

When you get the form for a new resource (/comic-books/new), or get the form to edit a resource (/comic-books/0/edit), you are asking for a forms-specific representation of the resource. If you post it to the resource collection with content-type "application/x-www-form-urlencoded" or "multipart/form-data", you are asking the server to save that type representation. The server can respond with the HTML representation which was saved, or whatever.

You may want to also allow for an HTML, XML, or JSON represention to be posted to the resource collection, for purposes of an API or similar.

It is also possible to represent your resources and workflow as you describe, taking into account covers posted after the comic book, but requiring comic books to have a cover. Example as follows.

  • Allows delayed cover creation
  • Allows comic book creation with required cover
  • Allows covers to be cross-referenced
  • Allows multiple covers
  • Create draft comic book
  • Create draft comic book covers
  • Publish draft comic book

GET /comic-books
=> 200 OK, Get all comic books.

GET /comic-books/0
=> 200 OK, Get comic book (id: 0) with covers (/covers/1, /covers/2).

GET /comic-books/0/covers
=> 200 OK, Get covers for comic book (id: 0).

GET /covers
=> 200 OK, Get all covers.

GET /covers/1
=> 200 OK, Get cover (id: 1) with comic book (/comic-books/0).

GET /comic-books/new
=> 200 OK, Get form to create comic book (form: POST /draft-comic-books).

POST /draft-comic-books
title=foo
author=boo
publisher=goo
published=2011-01-01
=> 302 Found, Location: /draft-comic-books/3, Redirect to draft comic book (id: 3) with covers (binary).

GET /draft-comic-books/3
=> 200 OK, Get draft comic book (id: 3) with covers.

GET /draft-comic-books/3/covers
=> 200 OK, Get covers for draft comic book (/draft-comic-book/3).

GET /draft-comic-books/3/covers/new
=> 200 OK, Get form to create cover for draft comic book (/draft-comic-book/3) (form: POST /draft-comic-books/3/covers).

POST /draft-comic-books/3/covers
cover_type=front
cover_data=(binary)
=> 302 Found, Location: /draft-comic-books/3/covers, Redirect to new cover for draft comic book (/draft-comic-book/3/covers/1).

GET /draft-comic-books/3/publish
=> 200 OK, Get form to publish draft comic book (id: 3) (form: POST /published-comic-books).

POST /published-comic-books
title=foo
author=boo
publisher=goo
published=2011-01-01
cover_type=front
cover_data=(binary)
=> 302 Found, Location: /comic-books/3, Redirect to published comic book (id: 3) with covers.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...