REST: Handling computed and related resource properties

Viewed 1247

Let's say I have a Wordpress-like blogging system with resources consisting of User, Post and Comment resources. Each of these resources is stored as a separate collection in a MongoDB database, and they are related to one another through ObjectID-valued fields. Specifically: a Post has an author field containing the ObjectID of its related User resource, and a Comment has an author field for the related user and a relatedPost field for the ObjectID of the post to which the comment applies.

Clearly, there are many instances where separately retrieving these resources will be inefficient. An example is displaying a particular Post resource client-side: ideally the name of that post's author should be displayed alongside the post title and body, but the Post document itself only contains the ObjectID of the related User document.

The simple solution is to retrieve these related properties on the server side and send additional data to the client. While that's a good solution for something simple like the blog I'm describing, it raises a few issues for more complicated systems. Specifically:

  • If GET /api/posts/#{postID} returns a JSON object with properties that are not really properties of the given Post document, how can I inform the client of this?
  • As an extension of the first issue: how can the client be informed that attempting to update a given field of that document with a POST to the same URI will not actually update the resource?
  • Would it be more appropriate for GET /api/posts/#{postID} to only return the properties really present on that document, with a secondary URI like /api/posts/#{postID}/withauthor returning the document plus related information?

More concretely, let's say these resources are defined by the following Mongoose.js-style schemas:

User: {
  _id: ObjectID,
  username: String,
  name: {
    first: String,
    last: String
  }
}

Post: {
  _id: ObjectID,
  author: ObjectID,
  title: String,
  body: String,
  timestamp: Date
}

Comment: {
  _id: ObjectID,
  author: ObjectID,
  relatedPost: ObjectID,
  title: String,
  body: String,
  timestamp: Date
}

I want a GET-able resource that returns a full representation of a Post document as well as the first and last name of the related author, so something like this:

request: GET /api/posts/529635f828ab08e00d000084

response: {
  _id: "529635f828ab08e00d000084",
  title: "A Post",
  body: "It turns out I have very little to say.",
  author: {
    _id: "928495a321cf09c11d198001",
    name: {
      first: "John",
      last: "Smith"
    }
  }

I don't want to lead the client to believe that updating author.name.first and POST-ing the JSON to the same URI is going to have any effect on the document's author attribute on the backend. Only an update to author._id should change the document's author. Is there a common "RESTful" approach to this?

I know there's no single correct answer here, and the simple approach I described earlier will work for this particular problem. But I'm curious as to how others have approached the issue in more complicated APIs.

(Note: there is a strong possibility that I'm overthinking this.)

1 Answers
Related