Не зацикливайтесь на бессмысленных нормах
Прежде чем я начну эту статью, я хотел бы сказать следующее: RESTful действительно хорош, но это просто архитектурный стиль программного обеспечения, и зацикленность на том, как соответствовать спецификации, просто раздражает и сводит на нет цель его использования в первую очередь.
Точно так же, как API Elasticsearch будет напрямую передавать JSON в GET-запросах, но это его бизнес-потребность, потому что обычный Query Param просто не может построить такой сложный DSL-запрос. В Github V3 API также есть много нестандартов, что не мешает ему стать эталонным стандартом для RESTful API в отрасли.
Некоторые из вещей, которые я представлю далее, также будут несовместимы со стандартом, но это вывод, с которым я сталкивался, беспокоился и обдумывал его в фактической разработке, так что эточто я думаю
Лучшие практики RESTful API.
Зачем использовать RESTful
Самое большое чувство, которое вызывает у меня RESTful, - это спецификация, простая для понимания и элегантная.Четкая структура и простой для понимания API могут полностью сэкономить много бессмысленного общения и документации. И RESTful сейчас становится все более и более популярным, и появляется все больше и больше отличных периферийных инструментов (таких как инструмент документации Swagger).
протокол
Если вы можете использовать HTTPS для всего сайта, конечно, это лучше всего.Если вы не можете, попробуйте использовать HTTPS для входа, регистрации и других интерфейсов, которые включают пароли.
Версия
Номер версии API не имеет ничего общего с номером версии клиентского приложения. Не позволяйте приложению передавать номер версии, который они используют для отправки рынка приложений на сервер, но предоставьте что-то вродеv1
,v2
Номера версий API, такие как . Номер версии разрешен только для перечисления, а не для оценки интервала.
Номер версии можно вставить в URL или разместить в шапке. Например:
api.xxx.com/v1/users
или:
api.xxx.com/users
version=v1
просить
Вообще говоря, внешняя форма API — это не что иное, как добавление, удаление, изменение и запрос (конечно, конкретная бизнес-логика определенно намного сложнее), а запрос делится на два типа: детали и списки. это эквивалентно общему шаблону. Например, при разработке API для статей самыми основными URL-адресами являются следующие:
-
GET /articles
: Список статей -
GET /articles/id
: Детали статьи -
POST /articles/
: создать статью -
PUT /articles/id
:изменить статьи -
DELETE /articles/id
: удалить статью
GET, POST, PUT и DELETE используются в RESTful для представления запроса ресурса, создания, изменения и удаления, и все три запроса, кроме POST, являются идемпотентными (эффект нескольких запросов одинаков). Следует отметить, что самая большая разница между POST и PUT заключается в идемпотентности, поэтому PUT также можно использовать для операций создания, если идентификатор ресурса можно определить до создания.
Одним из преимуществ размещения идентификатора в URL вместо параметра запроса является то, что он может представлять иерархическую связь между ресурсами. Например, под статьей будут комментарии и лайки. Эти два ресурса должны принадлежать статье. , поэтому их URL-адреса должны выглядеть так:
Комментарий:
-
GET /articles/aid/comments
: список комментариев к статье -
GET /comments/cid
: Получать -
POST /articles/aid/comments
: создание комментария к статье. -
PUT /comments/cid
: редактировать комментарий -
DELETE /comments/cid
: удалить комментарийЗдесь есть что-то особенное, всегда используйте кратчайший URL-путь, который может указывать на ресурс, т. е.
/comments/cid
Уже может указывать на комментарий, нет необходимости использовать его снова/articles/aid/comments/cid
Специально указал на статью.как:
-
GET /articles/id/like
: проверить, понравилась ли статья -
PUT /articles/id/like
: Понравилась статья -
DELETE /articles/id/like
: отменить лайк
Глаголы не рекомендуются в RESTful, поэтому это отношение можно сопоставить как ресурс. А поскольку большинство реляционных запросов связаны с текущим вошедшим в систему пользователем, реляционный статус также может быть возвращен непосредственно в ресурсе, которому принадлежит отношение. Например, подобный статус может быть возвращен непосредственно при получении сведений о статье. Обратите внимание, что я выбрал PUT вместо POST, потому что считаю, что поведение лайка должно быть идемпотентным, а результат нескольких операций должен быть одинаковым.
Жетон и знак
API должен быть спроектирован таким образом, чтобы он не сохранял состояние, поэтому клиент должен предоставлять действительный токен и подпись для каждого запроса.На мой взгляд, их цели:
- Токен используется для подтверждения того, что запрос принадлежит пользователю.Как правило, сервер случайным образом генерирует строку (UUID) после входа в систему и привязывает ее к вошедшему в систему пользователю, а затем возвращает ее клиенту. Как правило, существует два способа поддерживать состояние токена: один — продлевать или сбрасывать время жизни токена каждый раз, когда пользователь работает (аналогично механизму кэширования), другой — фиксированное время жизни токена, но в в то же время Возвращает токен обновления, который можно обновить вместо повторного входа в систему по истечении срока действия токена.
- Знак используется, чтобы доказать, что запрос является разумным, поэтому, как правило, клиент будет объединять и шифровать параметры запроса и передавать их на сервер в качестве знака, так что даже если пакет будет захвачен, другая сторона только изменяет параметры и не может сгенерировать соответствующий Знак, и он также будет отправлен сервером на сервер. Конечно, временная метка, адрес запроса и токен также могут быть смешаны с Sign, так что у Sign также есть владелец, своевременность и пункт назначения.
статистические параметры
Я не знаю точно, как должен называться такой параметр, короче, это различные приватности пользователя [ошибки. Подобно широте и долготе, системе мобильного телефона, модели, IMEI, статусу сети, версии клиента, каналу и т. д., эти параметры часто собираются и используются в качестве платформы для операций, статистики и т. д., но в большинстве случаев они не имеют отношения к бизнес. Такие параметры, которые меняются нечасто, могут быть отправлены при входе в систему, а те, которые меняются чаще, могут быть представлены путем ротации или в других запросах.
бизнес-параметры
В стандарте RESTful для операций модификации можно использовать как PUT, так и PATCH.Разница между ними заключается в том, что PUT нужно отправить весь объект, а PATCH нужно отправить только измененную информацию. Но, на мой взгляд, в практических приложениях такие заморочки не нужны, поэтому я всегда использую PUT и отправляю только модифицированную информацию.
Другой вопрос заключается в том, лучше ли использовать отправку формы или отправку JSON при отправке POST для создания объекта. На самом деле можно и то, и другое, на мой взгляд, единственная разница между ними в том, что JSON может легко представлять более сложные структуры (с вложенными объектами). Кроме того, независимо от того, какой из них вы используете, соблюдайте его согласованность и не смешивайте их.
Другое предложение состоит в том, что лучше всего предоставить клиенту всю необходимую информацию о фильтрации, разбиении по страницам и сортировке, включая условия фильтрации, количество страниц или курсоров, количество страниц на странице, метод сортировки, порядок возрастания и убывания и т. д., которые могут сделать API более гибким. Однако для условий фильтрации, методов сортировки и т. д. не обязательно поддерживать все методы, а только методы, которые используются в настоящее время, и те, которые могут быть использованы в будущем, и анализируются с помощью перечисления строк, чтобы видимость была лучше. . Например:
Для поиска клиент предоставляет только ключевые слова, конкретные поля поиска и метод поиска (префикс, полнотекстовый, точный) определяются сервером:
/users/?query=ScienJus
Фильтр, нужно только поддерживать существующую ситуацию:
/users/?gender=1
Для некоторой конкретной и сложной бизнес-логики вместо того, чтобы пытаться заставить клиента выражать сложные параметры запроса, используйте псевдонимы в URL-адресе:
/users/recommend
Разбивка на страницы:
/users/?offset=10&limit=10
/articles/?cursor=2015-01-01 15:20:30&limit=10
/users/?page=2&pre_page=20
Сортировка нужна только для поддержки существующей ситуации:
/articles/sort=-create_date
PS: мне нравится такое добавление перед именем поля-
Указывает, как сортировать в порядке убывания.
отклик
Попробуйте использовать коды состояния HTTP, обычно используемые:
- 200: запрос выполнен успешно
- 201: успешно создано и изменено
- 204: успешно удалить
- 400: ошибка параметра
- 401: Вы не вошли в систему
- 403: Запрещено
- 404 Не Найдено
-
500: системная ошибка
Но иногда невозможно четко выразить сообщение об ошибке, просто используя код состояния HTTP, поэтому я предпочитаю включать в него слой пользовательского кода возврата, например:
Об успехе:
{
"code": 100,
"msg": "成功",
"data": {}
}
При неудаче:
{
"code": -1000,
"msg": "用户名或密码错误"
}
data
это данные, которые действительно нужно вернуть, и они существуют только тогда, когда запрос выполнен успешно,msg
Используется только в среде разработки и только для идентификации разработчика. Логика клиента позволяет только идентифицироватьcode
, и не допускает прямогоmsg
контент, отображаемый пользователю. Если ошибка сложная и не может быть четко описана в абзаце, вы также можете добавитьdoc
поле, содержащее ссылку на документацию по ошибке.
возвращаемые данные
JSON лучше подходит для визуализации и меньше трафика, чем XML, поэтому старайтесь не использовать XML.
После успешного завершения операций создания и модификации необходимо вернуть всю информацию о ресурсе.
Возвращаемые данные не должны быть сильно связаны с клиентским интерфейсом.При разработке API не учитывайте, сколько повышения производительности может быть достигнуто за счет запроса на одну ассоциативную таблицу меньше или запроса/возврата на несколько полей меньше. И это должно быть в единицах ресурсов.Даже если клиентской странице нужно отобразить несколько ресурсов, не возвращайте их все в один интерфейс, а позвольте клиенту запрашивать несколько интерфейсов соответственно.
Лучше всего шифровать и сжимать возвращаемые данные, особенно в мобильных приложениях, где важно сжатие.
нумерация страниц
существуетВнутренний дизайн пейджинга приложенияКак упоминалось выше, макет подкачки обычно делится на два типа: один — это разбиение на страницы в лифте с нижней частью панели страниц, которое чаще встречается на веб-странице, а другой — более распространенная загрузка с подтягиванием. в приложении Больше потокового пейджинга. Как должны быть спроектированы эти два API подкачки?
Разбивка на страницы лифта должна быть предоставленаpage
(количество страниц) иpre_page
(количество на странице). Например:
/users/?page=2&pre_page=20
Сервер должен вернуть дополнительныйtotal_count
(общее количество записей), и опционально количество текущих страниц, количество страниц на страницу (эти две такие же, как и отправленные клиентом), общее количество страниц, есть ли следующая страница, есть ли предыдущая страницы (все три можно вычислить из общего количества записей). Например:
{
"pagination": {
"previous": 1,
"next": 3,
"current": 2,
"per_page": 20,
"total": 200,
"pages": 10
},
"data": {}
}
Таким образом можно использовать и поточную компоновку, при этом не нужно запрашивать общее количество записей (преимущество в том, что сокращается одна операция с базой данных, а недостаток в том, что клиенту нужно запрашивать еще раз, чтобы определить, перейти на последнюю страницу). Однако будет дублирование и отсутствующие данные, поэтому более рекомендуется использовать подкачку курсора.
Нужна нумерация курсораcursor
(начальный курсор на следующей странице) иlimit
(количество) параметр. Например:
/articles/?cursor=2015-01-01 15:20:30&limit=10
Если по умолчанию список статей отсортирован в обратном порядке по времени создания, тоcursor
Это время создания последнего элемента в текущем списке (первая страница — это текущее время).
Данные, которые должен вернуть сервер, также очень просты: ему нужно только общее количество записей из этого курсора в качестве начальной точки и следующего начального курсора. Например:
{
"pagination": {
"next": "2015-01-01 12:20:30",
"limit": 10,
"total": 100,
},
"data": {}
}
еслиtotal
меньше, чемlimit
, значит данных больше нет.
Другим распространенным случаем API подкачки потокового макета является добавочное обновление по запросу для обновления. Его бизнес-логика прямо противоположна подкачке курсора, но параметры в основном те же:
/articles/?cursor=2015-01-01 15:20:30&limit=20
Есть две возможности для возврата данных.Во-первых, если постепенно обновляемые данные меньше указанного количества, все данные будут возвращены напрямую (это количество может быть установлено относительно большим), и клиент добавит эти постепенно обновляемые данные. данные к существующим данным.Существует верхняя часть списка. Однако, если инкрементально обновляемые данные превышают указанный объем, в качестве первой страницы будут возвращены только последние n фрагментов данных, и клиенту необходимо очистить предыдущий список. Например:
{
"pagination": {
"limit": 20,
"total": 100,
},
"data": {}
}
еслиtotal
больше, чемlimit
, что указывает на то, что добавочных данных слишком много, поэтому возвращается только первая страница, а старый список необходимо очистить.