RESTful API URI Design

2019-03-09 04:26发布

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?

6条回答
你好瞎i
2楼-- · 2019-03-09 04:28

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>
查看更多
狗以群分
3楼-- · 2019-03-09 04:38

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]
查看更多
beautiful°
4楼-- · 2019-03-09 04:42

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.)

查看更多
我只想做你的唯一
5楼-- · 2019-03-09 04:50

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.

查看更多
时光不老,我们不散
6楼-- · 2019-03-09 04:52

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.

查看更多
爷的心禁止访问
7楼-- · 2019-03-09 04:55

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.

查看更多
登录 后发表回答