Alex Vayda
Alex Vayda

Reputation: 6494

REST: Desing pattern for different detalization levels of resource representation

I'm designing REST API for many resources I need to maintain at least 2 representations of the same format (e.g. JSON) which only differ in the amount of data they expose.

For example, I have books, publishers and authors which I'm exposing via REST. So I have 3 collection of resources:books, publishers and authors. When requesting a book I want it to include minimum information about its authors and publishers - just names, ids and hyperlinks to their full representation.

GET /books/12345
200 OK
{
    id: "12345",
    title: "My Book",
    authors: [
        {id:"111", name:"J. Smith", _href:"/authors/111"},
        {id:"222", name:"J.R.R. Tolkien", _href:"/authors/222"}
    ],
    publisher: {id:"333", name:"HarperCollins", _href:"/publishers/333"},
}

When user requests, e.g. /publishers/333 it should get more info about it, not just name and id:

{
    id: "333",
    name: "HarperCollins",
    address : { ... },
    contact : { ... },
    logo : { ... }
}

In my application I have 3 classes Book, Publisher and Author, where Book contain publisher and collection of authors. And I'm using Jackson and Spring MVC to expose all the entities as JSON via REST API.

@RequestMapping("/books/{id}")
@ResponseBody
public Book getBook(String id) {
    return getBookById(id);
}

@RequestMapping("/authors/{id}")
@ResponseBody
public Book getAuthor(String id) {
    return getAuthorById(id);
}

Now the questions:

Upvotes: 2

Views: 706

Answers (2)

Thomas
Thomas

Reputation: 1

1/ According to Spring MVC documentation, to serialize your object over HTTP you have to define your own class implementing HttpMessageConverter<T> with T either Book, Publisher or Author. http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/remoting.html#rest-message-conversion

2/ It is not necessary to split your objects in two. The logic to select what fields you pick up from an Author is contained in the AuthorToHttp implement HttpMessageConverter<Author>. Just need to develop a AuthorReferenceToHttp implement HttpMessageConverter<Author> to use when you want less data to be send over HTTP.

Another solution could be either AuthorReference extend Author or Author extend AuthorReference on one hand and AuthorToHttp implement HttpMessageConverter<Author> with AuthorReferenceToHttp implement HttpMessageConverter<AuthorReference> on the other hand to serialize your Author.

3/ Inheritance/Generalization is enough. Not necessarily a need for a pattern.

Composite is a wrong choice, you don't need a tree structure. According to circumstances you want either all data about an author - default behavior -, or the main data about an author - "proxied" behavior -. Proxy would be a better choice.

4/ No idea.

Upvotes: 0

Pete
Pete

Reputation: 11495

Have you considered using a more standard hypermedia format, such as HAL?

Doing so, it becomes pretty clear that you would have a difference between resources, and links to other resources. For example, it might end up as:

GET /books/123
200 OK
{
  "id": "123"
  "title": "My Book"
  "_links": {
     "author": [
       { "href": "/authors/111", "title": "J. Smith" },
       { "href": "/authors/321", "title": "Jules Verne" }
     ],
     "publisher": { "href": "/publishers/123", "title": "Harper Collins" }
  }
}

In terms of implementation, I would say you can either:

  1. Create custom DTO classes for each resource representation, along the lines of:

     public class BookDto {
         @JsonProperty(value="_links")
         public LinkCollection getLinks() { }
    
         public String getTitle() { }
     }
    
  2. Use the same classes, but use filters to modify the objects before Jackson serializes, and use some combination of @JsonProperty/@JsonIgnore.

Upvotes: 2

Related Questions