Рекомендации по проектированию RESTful API

задняя часть сервер API дизайн

оригинал:RESTful API Design. Best Practices in a Nutshell.
автор:Philipp Hauer


Как должен быть оформлен URL-адрес ресурса проекта? Существительные во множественном числе или в единственном числе? Сколько URL требуется для ресурса? Какой метод HTTP используется для создания нового ресурса? Где должны быть размещены необязательные параметры? Как насчет URL-адресов, которые не связаны с манипулированием ресурсами? Как лучше всего реализовать разбиение на страницы и управление версиями? Разработка RESTful API становится сложной из-за множества вопросов. В этой статье мы рассмотрим дизайн RESTful API и предложим передовое решение.

Используйте два URL-адреса для каждого ресурса

Коллекция ресурсов использует URL-адрес, а конкретный ресурс использует URL-адрес:

/employees         #资源集合的URL
/employees/56      #具体某个资源的URL

Используйте существительные вместо глаголов для представления ресурсов

Это делает ваш API чище и содержит меньше URL-адресов. Не проектируйте это таким образом:

/getAllEmployees
/getAllExternalEmployees
/createEmployee
/updateEmployee

лучший дизайн:

GET /employees
GET /employees?state=external
POST /employees
PUT /employees/56

Управление ресурсами с помощью HTTP-методов

Используйте URL-адрес, чтобы указать ресурс, который вы хотите использовать. Используйте метод HTTP, чтобы указать, что делать с этим ресурсом. Использование четырех HTTP-методов POST, GET, PUT, DELETE может обеспечить функциональность CRUD (создание, получение, обновление, удаление).

  • Получать: Используйте метод GET для получения ресурсов. Запросы GET никогда не изменяют состояние ресурса. Никаких побочных эффектов. Метод GET является идемпотентным. Метод GET предназначен только для чтения. Таким образом, вы можете использовать кеш отлично.
  • Создайте: Используйте POST для создания нового ресурса.
  • возобновить: Используйте PUT для обновления существующего ресурса.
  • Удалить: Используйте DELETE для удаления существующего ресурса.

2 URL-адреса, умноженные на 4 метода HTTP, — хороший набор функций. Взгляните на эту форму:

ПОСТ (создать) Читается) ПОСТАВИТЬ (обновить) УДАЛИТЬ (удалить)
/employees Создать нового сотрудника Список всех сотрудников Пакетное обновление информации о сотрудниках удалить всех сотрудников
/employees/56 (Ошибка) Получить информацию о сотруднике № 56 Обновление информации по сотруднику № 56 Удалить сотрудника № 56

Используйте метод POST для URL-адреса коллекции ресурсов, чтобы создать новый ресурс.

Как клиент взаимодействует с сервером при создании нового ресурса?

Используйте POST для URL-адреса коллекции ресурсов, чтобы создать новую процедуру ресурса.
  1. URL-адрес от клиента к коллекции ресурсов/employeesОтправьте POST-запрос. Тело HTTP содержит свойство «Альберт Старк» для нового ресурса.
  2. Веб-сервер RESTful генерирует идентификатор для нового сотрудника, создает сотрудника в своей внутренней модели и отправляет ответ клиенту. Заголовок HTTP этого ответа содержит поле Location, которое указывает URL-адрес, по которому можно получить доступ к созданному ресурсу.

Используйте метод PUT для URL-адреса определенного ресурса, чтобы обновить ресурс.

Используйте PUT для обновления существующих ресурсов.

  1. Клиент отправляет запрос PUT на URL-адрес определенного ресурса./employee/21. Тело HTTP-запроса содержит значение обновляемого атрибута (новое имя сотрудника 21 «Брюс Уэйн»).
  2. Сервер REST обновляет имя сотрудника с идентификатором 21 и использует код состояния HTTP 200, чтобы указать, что изменение было успешным.

Рекомендуемое использование нескольких существительных

рекомендовать:

/employees
/employees/21

Не рекомендуется:

/employee
/employee/21

На самом деле, это вопрос личных предпочтений, но чаще встречается множественное число. Кроме того, более интуитивно понятно использовать метод GET для URL-адреса коллекции ресурсов, особенноGET /employees?state=external,POST /employees,PUT /employees/56. Но самое главное: не смешивайте существительные во множественном и единственном числе, что может привести к путанице и ошибкам.

Для необязательных сложных параметров используйте строку запроса (?).

Не рекомендуемая практика:

GET /employees
GET /externalEmployees
GET /internalEmployees
GET /internalAndSeniorEmployees

Чтобы сделать ваши URL-адреса меньше и кратче. Задает базовый URL-адрес для ресурса, выражая необязательные сложные параметры в виде строки запроса.

GET /employees?state=internal&maturity=senior

Использование кодов состояния HTTP

Веб-службы RESTful должны отвечать на запросы клиентов соответствующими кодами состояния HTTP.

  • 2xx - успех - все хорошо
  • 4xx — Client Error — если на стороне клиента возникает ошибка (например, клиент отправляет неверный запрос или не авторизован)
  • 5xx — Server Error — если на сервере произошла ошибка (например, ошибка возникла при попытке обработать запрос) СсылкаКоды состояния HTTP в Википедии. Однако большинство этих кодов состояния HTTP не используются, используется лишь небольшое их количество. Обычно используются следующие:
    2xx: успех 3xx: перенаправление 4xx: ошибка клиента 5xx: ошибка сервера
    200 успехов 301 Постоянное перенаправление ошибка 400, неверный запрос внутренняя ошибка сервера 500
    201 Создать 304 Ресурс не изменен 401 Неавторизованный
    403 Запрещено
    404 Не Найдено

Возвращает полезные сообщения об ошибках

В дополнение к соответствующему коду состояния в теле ответа HTTP должно быть предоставлено полезное сообщение об ошибке и подробное описание. Вот пример. просить:

GET /employees?state=super

отклик:

// 400 Bad Request
{
    "message": "You submitted an invalid state. Valid state values are 'internal' or 'external'",
    "errorCode": 352,
    "additionalInformation" : 
    "http://www.domain.com/rest/errorcode/352"
}

Использовать верблюжий регистр

Используйте camelCase для идентификаторов атрибутов.

{ "yearOfBirth": 1982 }

Не используйте символы подчеркивания (year_of_birth) или Большой CamelCase (YearOfBirth). Как правило, веб-службы RESTful будут использоваться клиентами, написанными на JavaScript. Клиент преобразует ответ JSON в объект JavaScript (путем вызоваvar person = JSON.parse(response)), а затем вызвать его свойства. Поэтому лучше следовать общей спецификации кода JavaScript.
В сравнении:

person.year_of_birth // 不推荐,违反JavaScript代码通用规范
person.YearOfBirth // 不推荐,JavaScript构造方法命名
person.yearOfBirth // 推荐

Принудительно указывать номер версии в URL

Опубликуйте свой RESTful API с номерами версий. Необходимо указать номер версии в URL-адресе. Номера версий облегчат выпуск вашего API, если у вас есть несовместимые и критические изменения. При выпуске нового API просто увеличьте число в номере версии. Таким образом, клиенты могут легко перейти на новый API, не увязнув в вызове совершенно другого нового API.
Используйте интуитивный префикс «v», чтобы указать, что число, следующее за ним, является номером версии.

/v1/employees

Вам не нужно использовать дополнительный номер версии ("v1.2"), потому что вы не должны выпускать версии API слишком часто.

Предоставьте информацию о разбиении на страницы

Не рекомендуется сразу возвращать все ресурсы базы данных. Поэтому необходимо обеспечить механизм пейджинга. Обычно используются известные в базе параметры offset и limit.

/employees?offset=30&limit=15       #返回30 到 45的员工

Если клиент не передает эти параметры, следует использовать значения по умолчанию. Обычно значение по умолчаниюoffset = 0иlimit = 10. Должно быть уменьшено, если извлечение из базы данных происходит медленно.limitценность.

/employees       #返回0 到 10的员工

Также, если вы используете пагинацию, клиенту необходимо знать общее количество ресурсов. Пример: Запрос:

GET /employees

отклик:

{
  "offset": 0,
  "limit": 10,
  "total": 3465,
  "employees": [
    //...
  ]
}

Глаголы запроса без ресурсов

Иногда вызовы API не требуют ресурсов (таких как вычисления, переводы или преобразования). пример:

GET /translate?from=de_DE&to=en_US&text=Hallo
GET /calculate?para2=23¶2=432

В этом случае ответ API не вернет никаких ресурсов. Вместо этого выполните операцию и верните результат клиенту. Таким образом, вы должны использовать глаголы вместо существительных в URL-адресах, чтобы четко отличать запросы ресурсов от запросов, не связанных с ресурсами.

Рассмотрите возможность поиска по конкретным ресурсам и между ресурсами

Легко обеспечить поиск конкретного ресурса. Просто используйте соответствующий URL-адрес коллекции ресурсов и добавьте строку поиска к параметрам запроса.

GET /employees?query=Paul

Если вы хотите обеспечить глобальный поиск по всем ресурсам, вам нужно использовать другие методы. Как упоминалось ранее, для URL-адресов запросов, не связанных с ресурсами, используйте глаголы вместо существительных. Таким образом, ваш поисковый URL может выглядеть так:

GET /search?query=Paul   //返回 employees, customers, suppliers 等等.

Добавьте ссылки для просмотра других API в параметрах ответа.

В идеале клиенты не должны сами создавать URL-адреса, использующие REST API. Рассмотрим пример. Клиент хочет получить доступ к таблице заработной платы сотрудника. Для этого он должен знать, что может передать URL-адрес сотрудника (например,/employees/21/salaryStatements) для доступа к таблице зарплат, добавив строку «salaryStatements». Эта конкатенация строк подвержена ошибкам и ее трудно поддерживать. Если вы измените способ доступа к REST API для шкалы заработной платы (например, станете/employees/21/salary-statementили/employees/21/paySlips), все клиенты сломаются. Лучшим решением является добавлениеlinksполе, так что клиент может автоматически изменить.
просить:

GET /employees/

отклик:

//...
   {
      "id":1,
      "name":"Paul",
      "links": [
         {
            "rel": "salary",
            "href": "/employees/1/salaryStatements"
         }
      ]
   },
//...

Если клиент полностью полагается наlinksполе в таблице получения зарплаты, вы меняете API, клиент всегда будет получать действительный URL-адрес (пока вы меняетеlinkполе, запрошенный URL изменится автоматически) без нарушения. Еще одно преимущество заключается в том, что ваш API становится самоописываемым, что требует написания меньшего количества документации.
При разбивке на страницы вы также можете добавить примеры ссылок для перехода на следующую или предыдущую страницу. Просто предоставьте связанные примеры с соответствующими смещениями и ограничениями.

GET /employees?offset=20&limit=10
{
  "offset": 20,
  "limit": 10,
  "total": 3465,
  "employees": [
    //...
  ],
  "links": [
     {
        "rel": "nextPage",
        "href": "/employees?offset=30&limit=10"
     },
     {
        "rel": "previousPage",
        "href": "/employees?offset=10&limit=10"
     }
  ]
}

Связанное чтение: