5

Suppose I have two entities author and post, were every post has an author. Implemented are these REST calls

  1. Get a paginated list of posts: GET /posts?page={page}

  2. Get a list of authors: GET /authors

  3. Get a single author: GET /authors/{id}

Suppose I also have a client using the REST service. This client wants to show a paginated list of posts with related authors.

Now how would the REST service work regarding the related entities? There are the following methods:

  1. Let the GET /posts?page=1 call return the posts and the related authors in a single call. Optionally make this a separate parameter, f.e. GET /posts?page=1&related=true or GET /posts/related?page=1.

  2. Let the client loop through the posts and get the author for every post using the GET /author/{id} call.

  3. Let the REST call for the authors accept a list of ID's as a filter, so the client can get the related authors in one call, f.e. GET /authors?ids=10,12,16,30,43,44,58.

Method 1 is the easiest one from the client's perspective since it gets all the necessary data in one call. But the REST service is limited here, it shouldn't need to fit any particular client because every client has other requirements.

Method 2 is the cleanest REST approach, but let's say that a page has 30 posts, the client has to make 30 additional REST calls to retrieve the related authors. This is very inefficient.

Method 3 is perhaps better of the three, since it is a relatively clean REST implementation (compared to method 1) and it requires only one extra call per page.

Is there a recommended approach here?

3

That's, what links are for:

E.g. requesting the first post via GET http://example.com/posts/1

{
    "id": "1",
    "author": {
        "nickname": "me"
    },
    "links": [
        {
            "rel": "self",
            "href": "http://example.com/posts/1"
        },
        {
            "rel": "author",
            "href": "http://example.com/authors/me"
        }
    ]
}

The response contains a link to the author (named me). If you want to retrieve all of me's posts, you would do a GET to http://example.com/posts?author=me; and if you want it paginated, you would add a queryparameter like http://example.com/posts?author=me&page=1.

Say, you have collaborations between various authors, the initial answer would've been:

{
    "id": "1",
    "authors": [
        {
            "nickname": "me"
        },
        {
            "nickname": "mo"
        },
        {
            "nickname": "ma"
        }
    ],
    "links": [
        {
            "rel": "self",
            "href": "http://example.com/posts/1"
        },
        {
            "rel": "author",
            "href": "http://example.com/authors/me"
        },
        {
            "rel": "author",
            "href": "http://example.com/authors/mo"
        },
        {
            "rel": "author",
            "href": "http://example.com/authors/ma"
        }
    ]
}

On the other hand, under the links-section of the author, there should only be a reference to the latest post (to prevent too much data in there).

If you want to get a set of all collaborative posts from the trio above, you would query as follows:

GET http://example.com/posts?author=mo,me,ma

If you want all posts - including the collaborative - from the trio, you would query like this:

GET http://example.com/posts?author=mo|me|ma

This is a clean and straightforward approach.

To express, that something is related, you use links. If you want to filter you do it via querystring.

2

You could do something similar to what discogs do in their API, http://www.discogs.com/developers/#page:database,header:database-release. When requesting a release /releases/{release_id} the response also includes a subset of artist data, extract from the response body:

{    
    "title": "Never Gonna Give You Up",
    "id": 249504,
    "artists": [
        {
            "anv": "",
            "id": 72872,
            "join": "",
            "name": "Rick Astley",
            "resource_url": "https://api.discogs.com/artists/72872",
            "role": "",
            "tracks": ""
        }
    ]
}

In your case instead of artists it could be author and if the client want more info on the author they should of course use GET /authors/{id}.

0

You can also do it in one call by embedding authors inside posts. JSON Hypertext Application Language describes how to do this, see https://tools.ietf.org/html/draft-kelly-json-hal-06

e.g. (modified copy from the doc):

{
    "_links": {
        "self": { "href": "/posts" },
        "next": { "href": "/posts?page=2" },
        "find": { "href": "/posts{?id}", "templated": true }
    },
    "_embedded": {
        "post": [{
            "_links": {
                "self": { "href": "/posts/321" },
                "author": { "href": "/author/alan-watts" }
            },
            "_embedded": {
                "author": {
                    "_links": { "self": { "href": "/author/alan-watts" } },
                    "name": "Alan Watts",
                    "born": "January 6, 1915",
                    "died": "November 16, 1973"
                }
            }
            "title": "foo"
        }, {
            "_links": {
                "self": { "href": "/posts/123" },
                "author": { "href": "/author/alan-watts" }
            },
            "_embedded": {
                "author": {
                    "_links": { "self": { "href": "/author/alan-watts" } },
                    "name": "Alan Watts",
                    "born": "January 6, 1915",
                    "died": "November 16, 1973"
                }
            },
            "title": "bar"
        }]
    }
}
0

You may take some inspiration from the ODATA protocol as a variation to your option 1. It has so called query options one of which is $expand that takes the value of the related resource to return.

The $expand system query option specifies the related resources to be included in line with retrieved resources. The request below returns people with navigation property Posts of an Author.

GET /authors/{id}/$expand=Posts

http://www.odata.org/getting-started/basic-tutorial/#expand

You may create your own one called $related.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.