RESTful API URI Design
Asked Answered
S

6

13

I'm looking for some direction in regards to the URI design for a RESTful API. I'm going to have several nested linked resources and have currently designed my URI's similar to this post: Hierarchical RESTful URL design

The following example isn't what I'm building but I think illustrates my situation well. (Assume that a show can only belong to one network).

/networks [GET,POST]
/networks/{network_id} [GET,PUT]
/networks/{network_id}/shows [GET,POST]
/networks/{network_id}/shows/{show_id} [GET,PUT]
/networks/{network_id}/shows/{show_id}/episodes [GET,POST]
/networks/{network_id}/shows/{show_id}/episodes/{episode_id} [GET,PUT]

My situation will go two more levels further with associations but all the associations are one to many. I'm considering switching it to something similar to this:

/networks [GET,POST]
/networks/{network_id} [GET,PUT]
/networks/{network_id}/shows [GET,POST]

/shows [GET]
/shows/{id} [GET,PUT]
/shows/{id}/episodes [GET,POST]

/episodes [GET]
/episodes/{id} [GET,PUT]

My questions are:

  1. Is the second example a valid REST design?
  2. Should I consider implementing both paths?
Serpens answered 23/10, 2012 at 20:45 Comment(1)
Remember that you ultimately decide the structure for your RESTful API. It is your clients who will be using it. I think either are good, although obviously the first one is better at illustrating the hierarchy between networks, shows, and episodes. However, if the URIs are getting outrageously long, separating out to have those entities under / is not crazy either. I would ask yourself, what resources are actually going to be used the most. If it is episodes and shows, then putting them under the base makes a lot of sense.Paedo
C
6

The second example looks fine to me. The URLs are descriptive of the resources and the correct HTTP verbs are being used.

It is perfectly fine to have multiple URLs pointing to the same resource, if that makes sense. But more importantly, make sure the resources contain <link /> elements that connect shows to networks, episodes to shows, etc.

Counselor answered 23/10, 2012 at 20:51 Comment(2)
+1: I prefer xlink:href attributes myself, but <link> elements aren't a bad idea.Erection
Attributes work well in XML/XHTML but some representations like JSON do not support them. Anyway, the important thing is to take advantage of hypermedia to make services really RESTful.Counselor
N
3

The real question here: does your second example fulfill the URI standard? The URI standard states, that the path contains the hierarchical part and the query contains the non-hierarchical part, but afaik. it does not tell anything about how to design the URI structure in your situation. The REST uniform interface constraints has a HATEOAS section, which means that you should send back links in your situation, which point to the upper and lower level resources. You should annotate these links with metadata, which can be processed by the client, so it will know what a link is about. So in practice the URI structure does not really matter...

GET /shows/123

{
    "label": "The actual show",
    "_embedded": {
        "episodes": [
            {
                "label":  "The first episode of the actual show",
                "_embedded": {
                    "associations": [
                        //...
                    ]
                },
                "_links": {
                    "self": {
                        "label": "Link to the first episode of the actual show",
                        "href": "/episodes/12345"
                    },
                    "first": {
                        "href": "/episodes/12345"
                    },
                    "duplicate": {
                        "href": "/networks/3/shows/123/episodes/12345"
                    },
                    "up": {
                        "label": "Link to the actual show",
                        "href": "/shows/123"
                    },
                    "next": {
                        "label": "Link to the next episode of the actual show"
                        "href": "/episodes/12346"
                    },
                    "previous": null,
                    "last": {
                        "href": "/episodes/12350"
                    }
                }
            }//,
            //...
        ]
    },
    "_links": {
        "self": {
            "label": "Link to the actual show",
            "href": "/shows/123"
        },
        "duplicate": {
            "href": "/networks/3/shows/123"
        },
        "up": {
            "label": "Link to the actual network",
            "href": "/networks/3"
        },
        "collection": {
            "label": "Link to the network tree",
            "href": "/networks"
        },
        "next": {
            "label": "Link to the next show in the actual network",
            "href": "/shows/124"
        },
        "previous": {
            "label": "Link to the previous show in the actual network",
            "href": "/shows/122"
        }
    }
}

Now this is just something very beta in HAL+JSON with IANA link relations, but you can use JSON-LD with an RDF vocabulary (e.g. schema.org+hydra) as well. This example is just about the hierarchy (up, first, next, previous, last, collection, item, etc...), but you should add more metadata e.g. which link points to a network, which to a show, and which to an episode, etc... So your clients will know from the metadata what the content is about, and for example they can use the links to navigate automatically. This is how REST works. So the URI structure does not really matters by the client. (You can use compact URIs and URI templates as well if you want to make your response more compact.)

Noranorah answered 9/1, 2015 at 15:30 Comment(0)
C
1

Considering you have one-to-many relationships in following hierarchy:

network --> shows --> episodes

I think the second design does not provide sufficient information to the Server side to process your request. For example if you have following data:

Network id  show_id episode_id
    1         1        1
    1         2        1
    1         1        2

The first design which is verbose will provide sufficient information in HTTP request to fetch data: /networks/1/shows/1/episodes/1

The second design on the contrary will have:

/episodes/1 

In the second design there is no way for server side to know if you meant row1 or row 2 from your data

To answer your question:

  1. IMHO 2nd design may not be a valid REST design for your example. A workaround may be to pass query parameters

  2. I think design 1 is self sufficient

UPDATE: Please ignore my answer above

  1. 2nd design is a valid REST design for your example
  2. Only having design 2 should also suffice

Additionally:

/networks
/networks/{id}

/shows
/shows/{id}

/episodes
/episodes/{id}

should be sufficient number of REST URLs

or in other words the following URLs would be redundant:

/networks/{network_id} [GET,PUT]
/networks/{network_id}/shows [GET,POST]

/shows/{id}/episodes [GET,POST]
Commandeer answered 23/10, 2012 at 21:3 Comment(5)
Dear Vikram, correct me if I misunderstood, are you suggesting that episodes correct design would require a 3 column composite primary key?Ketone
@AlessandroOliveira thanks for your comment. Your comment helped me understand how second design in the question is also a valid design!! To answer your question: the 3 column composite primary key was just a representation to understand relationship between these 3 hierarchical entities. I dont mean to recommend it...Commandeer
also another thing that I'm very concerned is about exposing primary keys as object ID's, I think that even though the system having authentication and authorization measures in place, these implementation decisions should not be exposed in any way. But since I'm an UUID advocate, my position can be considered a little biased.Ketone
@AlessandroOliveira I agree with youCommandeer
You had it right on the 1st try IMO. If an episode can't be determined without knowing the show, it doesn't make sense to have an /episodes route. Only if they do have unique IDs all by themselves, but even then I'd question the usefulness.Wandy
A
1

A URI is "any information that can be given a name"

Your question is a domain related question, and can only really be answered by someone who knows about the resources with which you are naming with a URI.

The question that comes to mind while trying to guess about your domain, is does a "show" really depend on a "network"?

What is a network in your domain? and what is the relationship between a show and a network? Is it simply someone who has aired the show? or is it more to do with production information?

I believe your example 2 is a much better fit.

Any answered 23/10, 2012 at 21:17 Comment(1)
You had me in the 1st half, then ruined it with the last sentence. If episodes don't exist without giving the show ID, then it doesn't make much sense to expose them from the root. Shows might exist without a network though, so it makes sense there.Wandy
S
0

I think we should keep REST API URL as simple as we can.

e.g. https://www.yoursite.com/api/xml/1.0/

Here I'm taking example of XML API for version 1.0. Please remember to use versions of the API for future updates.

You can check the method which is requested by the client.

e.g. tag

<method>getEpisodes</method>
Sullage answered 23/10, 2012 at 21:21 Comment(2)
That doesn't look especially RESTful, but rather very SOAPy (which is OK if that's what you're doing, but SOAP and REST are very different approaches to structuring the application…)Erection
My major concern was the version of the API. e.g. My stable API release version is 1.2 and my clients are using the same in their applications. Now we enhanced our API (version 1.4) and deprecated some functionality of the API which was supported in version 1.2. My clients whom are using version 1.2 will get the error for the deprecated functionality. Please let me know your thought.Sullage
G
0

I think the second option is Ok, but if you wanted to validate relationships, I would consider the first option. For example, when you get an episode with a different network, it can mean that the episode was modificated before your request so maybe you need to response with a 422, the same for the others services. With this, you can be sure that the entity you want to work is involving its parent.

PD: Sorry for my English.

Ganiats answered 9/1, 2015 at 17:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.