Michael Cordell's Blog

REST API and related object creation

22 Oct 2014

While building a REST API I began examining th issue of creating child objects that do not already have a parent object created. Consider the following scenario: Books have one author and author’s have many books. What happens when you want to add a book but have not yet created the author resource. Further, what happens if you do not want to add an author without at least one book?

I see the following options for solving this scenario:

1. Create an author resource first

This requires relaxing the enforcement of the “Authors have 1 or more books” requirement. Further, it requires two requests to make a book.

POST /authors

{"first_name": "John", "last_name": "Steinbeck"}

Receive:

{
  "id": 3,
  "first_name": "John",
  "last_name": "Steinbeck"
}

Then create a book for the author:

POST /authors/3/books

{"name": "The Grapes of Wrath" }

2. Create the author and book in one request:

POST /authors

  {
      "first_name": "John",
      "last_name": "Steinbeck",
      "books": {
          {
              "name": "The Grapes of Wrath"
          }
      }
  }

This method seems to be the most suitable as it maintains the 1..N requirement for authors and it accomplishes the task in one request. My only qualm is that if the focus is on the creation of the book this request shifts the focus to the author. Two minor problems arise here, one: perhaps the author object is incomplete at the stage of this request (i.e. perhaps the author has another child model) and secondly the response will be focused on the author and not the book.

3. Create an intermediary model

This idea arises from this stack overflow post, wherein you build up the parent object as a “draft” object first and then add the child object and finally save the “real” object. This would like:

POST /draft-authors

{"first_name": "John", "last_name": "Steinbeck"}

Receive

{
  "id": 3,
  "first_name": "John",
  "last_name": "Steinbeck"
}

Then create a book for the author:

POST /draft-authors/3/books

{"name": "The Grapes of Wrath"}

Then save the author

POST /save-author

  {
      "first_name": "John",
      "last_name:" "Steinbeck",
      "books": {
          {
              "name": "The Grapes of Wrath"
          }
      }
  }

This might seem like the worst of both worlds, but this also could be the most robust method in that it allows for a complex parent model and children to be built up slowly. I think it is worth examining in very specific data scenarios.

comments powered by Disqus