중첩 REST URL과 부모 ID, 더 나은 디자인은 무엇입니까?


20

좋아, 우리는 두 가지 자원을 가지고 AlbumSong. API는 다음과 같습니다.

GET,POST /albums
GET,POST /albums/:albumId
GET,POST /albums/:albumId/songs
GET,POST /albums/:albumId/songs/:songId

우리는 우리가 어떤 노래를 싫어한다는 것을 알고 Susy있습니다. 우리는 어디에 search행동 을해야 합니까?

다른 질문. 이제 더 현실입니다. 앨범 1을 열고 모든 노래를로드합니다. 우리는 JS 객체를 생성하고 각각 노래 데이터를 보유하며 다음과 같은 방법이 거의 없습니다 : remove, update.

노래 개체에는 ID, 이름 및 항목이 있지만 쿼리로 노래 목록을 검색하므로 부모 ID를 반환하는 것이 좋지 않기 때문에 어떤 부모가 속하는 지에 대한 실마리가 없습니다. 내가 잘못?

따라서 해결책이 거의 없지만 확실하지 않습니다.

  1. 부모 ID를 선택적으로 get-parameter로 설정하십시오. 이 접근법은 현재 사용하고 있지만 그 방법이 추악하다고 생각합니다.

    List,Create /songs?album=albumId
    Update,Delete /songs/:songId
    Get /songs/?name=susy # also, solution for first question
    
  2. 잡종. OPTIONS메타 데이터를 얻기 위해 쿼리를 수행하려면 앨범 ID가 필요하기 때문에 편리 합니다.

    List,Create /album/:albumId/songs
    Update,Delete /songs/:songId
    POST /songs/search # also, solution for first question
    
  3. 각 리소스 인스턴스와 함께 전체 URL을 반환합니다. API는 동일하지만 다음과 같은 노래가 표시됩니다.

    id: 5
    name: 'Elegy'
    url: /albums/2/songs/5
    

    이 접근법을 HATEOAS라고 들었습니다.

  4. 그래서 ... 부모 ID를 제공하려면

    id: 5
    name: 'Elegy'
    albumId: 2
    

어떤게 더 좋아? 아니면 어리석은가? 몇 가지 조언을 던져!

답변:


31

검색 액션을 어디에 두어야합니까?

에서 GET /search/:text. 그러면 일치하는 앨범이 포함 된 모든 일치 항목이 포함 된 JSON 배열이 반환됩니다. 클라이언트가 트랙 자체가 아니라 전체 앨범에 관심이있을 수 있기 때문에 이것은 의미가 있습니다.

부모 ID를 각각 반환하는 것은 좋지 않습니다. 내가 잘못?

개별 트랙에는 앨범이 포함될 수 있습니다. 이렇게하면 앨범이나 검색 (여기서는 앨범 없음)을 통해 트랙을 얻을 수있는 경우 트랙 표현이 균일해야합니다.

어떤게 더 좋아?

앞에서 언급했듯이 앨범을 포함하는 것이 좋습니다. 세 번째 요점 (상대 URI가있는)은 경우에 따라 흥미로울 수 있지만 (URI가 형성되는 방식에 대해 생각할 필요는 없지만) 앨범을 명시 적으로 제공하지 않는 단점이 있습니다. 네 번째 요점이이 문제를 해결합니다. 응답에 상대 URI가 있다는 이점이 있으면 포인트 3과 4를 결합 할 수 있습니다.

아니면 어리석은가?

올바른 URI가 없기 때문에 좋은 URI를 선택하는 것은 쉬운 일이 아닙니다. API와 동시에 클라이언트를 개발하면 API 사용 방법을 더 잘 시각화하는 데 도움이 될 수 있습니다. 즉, 다른 사람들은 API를 개발할 때 생각하지 않은 다른 사용법을 선호 할 수 있습니다.

문제가 될 수있는 측면은 내부적으로 데이터를 구성하는 방법, 즉 계층 구조 사용입니다. 귀하의 의견에서에 대한 응답을 포함해야 할 것이 무엇인지 궁금합니다 GET /artist/1/album/10/song/3/comment/23. 이는 매우 트리 지향 비전을 보여줍니다. 나중에 시스템을 확장 할 때 몇 가지 문제가 발생할 수 있습니다. 예를 들어 :

  • 노래에 앨범이 없으면 어떻게 되나요?
  • 앨범에 여러 아티스트가있는 경우 어떻게합니까?
  • 앨범에 댓글을 달 수있는 기능을 추가하려면 어떻게해야합니까?
  • 의견에 대한 의견이 있으면 어떻게해야합니까?
  • 기타

이것은 본질적으로 내 블로그에서 설명 한 문제입니다 . 트리 표현에는 많은 경우 효과적으로 사용하기에는 너무 많은 제한이 있습니다.

계층을 파괴하면 어떻게됩니까? 보자

  1. GET /albums/:albumId앨범에 대한 메타 정보 (예 : 앨범을 게시 한 연도 또는 앨범 표지를 표시하는 JPEG의 URI 등) 및 트랙 배열이 포함 된 JSON을 반환합니다. 예를 들면 다음과 같습니다.

    GET /albums/151
    {
        "id": 151,
        "gid": "dbd3cec7-b927-423f-894b-742c4c7b54ce",
        "name": "Yellow Submarine",
        "year": 1969,
        "genre": "Psychedelic rock",
        "artists": ["John Lennon", "Paul McCartney", ...],
        "tracks": [
            {
                "id": 90224,
                "title": "Yellow Submarine",
                "length": "2:40"
            },
            {
                "id": 83192,
                "title": "Only a Northern Song",
                "length": "3:24"
            }
            ...
        ]
    }

    예를 들어 각 트랙의 길이를 왜 포함시켜야합니까? 타이틀을 기준으로 트랙을 나열하면 앨범을 보여주는 고객이 관심을 가질 수 있다고 생각하지만 각 트랙의 길이도 보여줍니다. 다른 한편으로, 나는이 정보가이 레벨에서 필요하지 않다고 결정하기 때문에 모든 트랙에 대해 작곡가 나 아티스트를 보여주지 않을 수 있습니다. 분명히, 당신의 선택은 다를 수 있습니다.

  2. GET /tracks/:trackId특정 트랙에 대한 정보를 반환합니다. 더 이상 계층이 없기 때문에 앨범이나 아티스트를 추측 할 필요가 없습니다. 실제로 알아야 할 것은 트랙 자체의 식별자뿐입니다.

    아니면 어쩌면? 이름으로 이름을 지정할 수 있으면 어떻게 GET /tracks/:trackName합니까?

    GET /tracks/Only%20a%20Northern%20Song
    {
        "id": 83192,
        "gid": "8d9c4311-9d7b-40a4-8aeb-4fe96247fe2b",
        "title": "Only a Northern Song",
        "writers": ["George Harrison"],
        "artists": ["John Lennon", "Paul McCartney", "Ringo Starr"],
        "length": "3:24",
        "record-date": 1967,
        "albums": [151, 164],
        "soundtrack": {
            "uri": "http://audio.example.com/tracks/static/83192.mp3",
            "alias": "Beatles - Only a Northern Song.mp3",
            "length-bytes": 3524667,
            "allow-streaming": true,
            "allow-download": false
        }
    }

    이제 좀 더 자세히 살펴보십시오 albums. 당신은 무엇을 봅니까? 한 장이 아니라 두 장의 앨범. 계층 구조가 있으면 레코드를 복제하지 않는 한 그렇게 할 수 없습니다.

  3. GET /comments/:objectGid. 응답에서 추악한 GUID를 발견했을 수 있습니다. 이러한 GUID를 사용하면 앨범, 아티스트 또는 트랙에 적용 할 수있는 작업을 수행하기 위해 데이터베이스에서 엔터티를 식별 할 수 있습니다. 댓글 달기 등.

    GET /comments/8d9c4311-9d7b-40a4-8aeb-4fe96247fe2b
    [
        {
            "author": {
                "id": 509931,
                "display-name": "Arseni Mourzenko"
            },
            "text": "What a great song! (And I'm proud of the usefulness of my comment)",
            "concerned-object": "/tracks/83192"
        }
    ]

    주석은 관련 객체를 참조하므로 컨텍스트 외부에서 주석에 액세스 할 때 (예 :을 통해 최신 주석을 검토 할 때) 해당 객체로 이동할 수 있습니다 GET /comments/latest.

그렇다고 API에서 계층 구조를 피해야한다는 의미는 아닙니다. 말이되는 경우가 있습니다. 경험적으로 볼 때 :

  • 자원이 상위 자원의 컨텍스트 외부에서 의미가 없으면 계층 구조를 사용하십시오.

  • 자원이 (1) 단독으로 또는 (2) 유형이 다른 상위 자원의 컨텍스트에서 살 수 있거나 (3) 여러 상위가있는 경우 계층 구조를 사용해서는 안됩니다.

예를 들어, 파일 행은 파일 컨텍스트 외부에서 의미가 없으므로 다음과 같습니다.

GET /file/:fileId

과:

GET /file/:fileId/line/:lineIndex

괜찮아.


그러나 검색을 통해 전체 앨범 정보를 반환 할 수 있으며 다른 리소스를 만들 SongSearchResult것입니다. 그러나 URL은 무엇입니까? parentID각 객체를 제공 하고 GET 매개 변수 또는 URL의 정상적인 부분으로 사용해야합니까? 깊이가 2보다 크면 어떻게해야합니까? /artist/1/album/10/song/3/comment/23-아티스트, 앨범 및 노래의 모든 ID를 대상으로 제공하는 것은 미친 comment일이지만, 그것이 갈 길이라고 들었지만 어지럽 지 않습니까?!
dt0xff

@ dt0xff : 내 대답을 편집했습니다. 깊이를 피할 수있는 방법에 대한 명확한 이미지를 제공해야한다고 생각합니다.
Arseni Mourzenko

그러나 이제 URL로 부모에 추가하지 않고 각 리소스 (라인 또는 다른 기능적인 것 제외)에 대한 진입 점을 구현하는 것이 훨씬 쉽다는 것이 분명합니다. 고맙습니다, 당신은 저의 선택이 옳았 고 "공통적 인 접근"(실제로 많은 중첩 된 것들이 restangular만들어져 있음)이 그렇게 좋지 않다고 확신했습니다.
dt0xff

좋은 대답입니다. 그래도 몇 가지 반대 의견이 있습니다. "앨범에 여러 아티스트가있는 경우 어떻게합니까?" 이진 관계 URI-> 자원이 고유 (다 대일)하기 때문에 다른 URI가 동일한 자원을 식별 할 수 있습니다 . URI를 따라서 /artists/foo/albums/qux/artists/bar/albums/qux완벽하게 같은 앨범 자원을 식별 할 수 있습니다. 즉, URI의 경로 구성 요소는 그래프 계층 구조를 나타내며 , 반드시 트리 계층 구조는 아니기 때문에 범주뿐만 아니라 태그도 나타내는 데 적합합니다.
Maggyero

1
… "이것은 본질적 으로 내 블로그에서 설명한 문제입니다 . 트리 표현에는 많은 경우에 효과적으로 사용하기에는 너무 많은 제한이 있습니다." 그래서, 이것은 문제가되지 않습니다. "앨범에 댓글을 달 수있는 기능을 추가하려면 어떻게해야합니까?" 그것은 또한 문제가되지 않습니다 : /artists/foo/albums/qux/comments/7. "댓글에 댓글이 있으면 어떻게해야합니까?" 마찬가지로 /artists/foo/albums/qux/song/5/comments/2/comments/8.
Maggyero
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.