2

我在 Django 中有两个模型:

class Thread(models.Model):
    entity = models.ForeignKey(Entity, null=True, blank=True)
    ...

class ThreadMessage(models.Model):
    thread = models.ForeignKey(Thread, related_name='messages')
    author = models.ForeignKey(User)
    ...

现在客户想要创建一个包含第一条消息的新线程。它必须首先POST /threads创建一个新线程并找出它id,然后在字段POST /messages中传递找到的 id 。thread

我正在考虑是否可以在 Ember 的一个请求中完成所有这些操作,例如:

POST /messages 
{"message": {"text": "text", ...},
 "thread":  {"entity": 1}}

回应是:

{"message": {"text": "text", "id": 5678, "thread": 1234, ...},
 "thread":  {"entitity": 1, "id": 1234, ...}}
4

2 回答 2

5

是的,这是完全合理的。

People seem to interpret REST in a very strange and largely ignorant way. A cursory read of the HTTP RFC 7231 for POST and PUT will confirm you are on solid ground.

A resource representation can represent ANYTHING. The key thing is to preserve the semantics of the REST operations. So PUT can be used for both CREATE and REPLACE like operations (I tend to think of PUT being REPLACE rather than UPDATE as REPLACE is closer to an idempotent semantic than UPDATE in my mind)

A PUT to an endpoint where supported, should accept whatever representation a GET returns. A POST can do literally anything you want as it doesn't need to support idempotent semantics.

HTTP and REST is designed and intended to support resource representations that may overlap other resources and the RFC is explicit about this. You do this all the time when doing a GET on a collection endpoint.

You are NOT breaking REST by having a thread containing a child message in a single request and IMO that is a very valid use use case for sane referential integrity on the server. Any time a transactional semantic is required, a POST or PUT is perfectly valid to create a graph of objects on the server in a single request. It is really simple, if you can GET it in a single request, you should be able to PUT it in a single request, so think carefully about your URL's and parameters.

For example, you may have a thread endpoint that returns all messages and that endpoint may support a parameter to just return some subset of the information /api/threads?include=hasRead which returns just id and hasRead for each message in the thread, or perhaps just some range of 'pages'. You can then PUT using that same endpoint and parameters and just update thehasRead property in bulk.

Anyone who gets hung up on this has probably never considered access controls either. Access control necessitates a different view of a resource from one user to another based on what they are allowed to access. This different view of a resource is conveyed in HTTP auth headers and/or in the request URL; again REST is not being broken by sub-setting or overlapping resources.

So go ahead and create the minimal graph of objects you need and either PUT or POST them. I use V4 UUID's so clients can assign ID's (and thus resource endpoints) themselves and this allows me to use PUT for both create and replace like actions and wire up complex object graphs without client<->server id mapping issues.

于 2014-12-27T10:48:46.923 回答
-4

您要做的将是打破 REST 和 EmberJS 本身的概念。

如果您有两个单独的 APIyou should make two REST calls.

先保存父thread模型,成功返回后保存子模型message。然后使用addObject来反映视图的变化。

这是最好的方法。不要试图通过减少这里的 API 调用和破坏 REST 来进行优化。

于 2014-12-26T06:44:51.593 回答