Где мы должны поставить поисковое действие?
В GET /search/:text
. Это вернет массив JSON, содержащий совпадения, каждое совпадение, содержащее альбом, которому он принадлежит. Это имеет смысл, потому что клиент может интересоваться не самим треком, а всем альбомом (представьте, что вы ищете песню, которая, как вы полагаете, была в том же альбоме, что и тот, который вы помните по имени).
будет не так хорошо возвращать родительские идентификаторы для каждого из них. Я ошибаюсь?
Отдельные треки могут содержать альбом. Это обеспечит равномерное представление трека, если вы можете получить трек либо через альбом, либо через поиск (здесь нет альбома).
Что лучше?
Как уже говорилось, в том числе альбом имеет смысл. Хотя третий пункт (с относительным URI) может быть интересен в некоторых случаях (вам не нужно думать о том, как должен формироваться URI), у него есть недостаток, заключающийся в том, что он не предоставляет явно альбом. Четвертый пункт исправляет это. Если вы видите преимущество наличия относительного URI в ответе, вы можете объединить пункты 3 и 4.
А может я тупой?
Выбор хороших URI не является легкой задачей, тем более что единого правильного ответа не существует. Если вы разрабатываете клиент одновременно с API, это может помочь вам лучше представить, как можно использовать API. При этом другие люди могут тогда предпочесть другие способы использования, о которых вы не думали при разработке API.
Аспект, который может быть проблематичным, заключается в том, как вы организуете данные внутренне, то есть используете иерархию. Из вашего комментария вам интересно, что должно содержать ответ GET /artist/1/album/10/song/3/comment/23
, который показывает очень древовидное видение. Это может привести к нескольким проблемам при дальнейшем расширении системы. Например:
- Что если у песни нет альбома?
- Что если в альбоме есть несколько исполнителей?
- Что если вы хотите добавить функцию, которая позволяет комментировать альбомы?
- Что делать, если должны быть комментарии комментариев?
- и т.п.
По сути, это проблема, которую я объяснил в своем блоге : представление дерева имеет слишком много ограничений, чтобы его можно было эффективно использовать во многих случаях.
Что произойдет, если вы разрушите иерархию? Посмотрим.
GET /albums/:albumId
возвращает JSON-файл, содержащий метаинформацию об альбоме (например, год, когда он был опубликован, или URI в формате JPEG с обложкой альбома) и массив дорожек. Например:
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"
}
...
]
}
Почему я включаю, например, длину каждого трека? Потому что я представляю, что клиент, показывающий альбом, может быть заинтересован, перечисляя треки по названию, но также показывая длину каждого трека - большинство клиентов это делают. С другой стороны, я не могу показывать композитора (ов) или исполнителя (исполнителей) для каждого трека, потому что я решаю, что эта информация не нужна на этом уровне. Очевидно, ваш выбор может быть другим.
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
; что ты видишь? Да, не один, а два альбома. Если у вас есть иерархия, вы не можете этого сделать (если только вы не дублируете запись).
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
- безумно указывать каждый идентификатор исполнителя, альбома и песни наcomment
объекте, но я слышал, что это путь, но разве это не ужасно ?!