Это не нормально. Это нужно прекратить сейчас!

Этот блог не должен быть разглагольствованием, но начните с того, что посмотрите правде в глаза — многие бэкенд-разработчики полностью проигнорировали основные принципы проектирования REST и лучшие практики.

Сегодня я столкнулся с некоторыми пугающими конечными точками, такими как /getAllSubsections и /deleteContactOfUser 😱 в проекте Node.js, что побудило меня написать этот блог и затронуть основные принципы проектирования REST API.

Начнем с констатации очевидного. REST API — это API, который соответствует принципам проектирования REST или архитектурному стилю репрезентативной передачи состояния. REST обеспечивает высокий уровень гибкости, масштабируемости и свободы, поэтому на сегодняшний день он стал наиболее используемой архитектурой API.

Если вы не знаете, что такое API, прочитайте это, а затем вернитесь сюда.

REST API можно разрабатывать на любом языке программирования, в отличие от SOAP или XML-RPC. Единственное требование состоит в том, чтобы они соответствовали шести принципам проектирования REST, также известным как архитектурные ограничения.

Концепции

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

Ресурсы

Ресурс — это объект с типом, связанными данными, связями с другими ресурсами и набором методов, которые с ним работают.

Обычно все, что может быть названо, может считаться ресурсом. Например, рассмотрим ресурсы на Medium. Если вы посмотрите на API Medium, мы увидим следующие 4 ресурса —

Обратите внимание, что при разработке своего API вы можете самостоятельно принимать решения относительно того, что должно быть выделено в качестве ресурса. Это решение повлияет на соответствующую сложность и структуру вашего API.

URL-адреса на основе ресурсов

При разработке конечных точек или URL-адресов для вашего API нам необходимо убедиться, что они хорошо структурированы и основаны на ресурсах, которые мы определили выше.

HTTP-методы

Как обсуждалось в определении ресурса, он связан с набором методов, которые могут работать с ним. Наиболее распространенными глаголами HTTP являются GET, POST, PUT, PATCH,иDELETE.

Важный пример

Предположим, что гипотетически конечные точки Medium API выглядели так, как показано ниже. Операции, которые мы пытаемся выполнить с помощью первых 4 конечных точек, — это создание, чтение, обновление и удаление блогов. .

Вышеупомянутые конечные точки - беспорядок по следующим причинам:

  1. URL-адреса плохо структурированы и содержат гораздо больше, чем просто название ресурса (существительные).
  2. Создание конечных точек, таких как /getAllSubsections (как я упоминал во введении), — это кошмар, поскольку подразделы — это нечетко определенные ресурсы.
  3. Добавление глаголов к URL-адресам может быстро сделать управление невозможным. Теперь у нас есть 4 новые конечные точки вместо одной, она же /blogs. Это число будет только увеличиваться по мере того, как мы начинаем иметь дело с другими ресурсами.
  4. Для сложных или вложенных запросов, таких как получение всех пользовательских публикаций или создание публикации под публикацией, URL-адреса будут огромными. Представьте себе сценарий, когда нам нужно 3 или 4 уровня вложенности!

Итак, что нам здесь не хватает? Конечные точки должны содержать только ресурсы (существительные) и использовать методы HTTP для действий! Вот как должны выглядеть конечные точки после их исправления. Позже вы узнаете, что это ограничение называется Унифицированный интерфейс. Также обратите внимание, что мы используем существительные во множественном числе для создания URL-адресов из ресурсов по соглашению. Поэтому мы используем \blogs, а не \blog.

Для вложенного случая, скажем, если мы хотим получить все публикации для определенного пользователя, мы будем использовать что-то вроде —

GET /users/{{userId}}/publications

Здесь userId — уникальный идентификатор конкретного пользователя. Вы можете видеть, что Medium действительно использует эту конечную точку для той же цели!

Отправлять данные в формате JSON (обычно)

JSON (обозначение объектов JavaScript) — это облегченный формат обмена данными. Обычно при взаимодействии клиента и сервера любые передаваемые данные должны быть в формате JSON. Кроме того, отправляемые данные должны соответствовать некоторым спецификациям, таким как JSend (наиболее распространенный), JSON: API или протокол OData JSON.

Базовый ответ, совместимый с JSend, очень прост. Вы можете прочитать больше здесь".

{
    status : "success",
    data : {
        "post" : { "id" : 1, "title" : "A blog post", "body" : "Some useful content" }
     }
}

Быть без гражданства

REST API не должны иметь состояния. Все состояние обрабатывается на стороне клиента. Каждый запрос должен содержать всюинформацию, необходимую для обработки конкретного запроса. Сервер не должен запоминать предыдущие запросы.

Например, предположим, что в данный момент вы просматриваете все блоги на странице номер 6. Если вы хотите прочитать блоги на странице семь, то запрос ниже не позволяет

GET /blogs/nextPage  -- bad practice 

сервер не имеет состояния. Это связано с тем, что некоторые данные должны храниться на стороне сервера, чтобы отслеживать, какая страница была последней отправлена ​​в ответ на предыдущий запрос. С другой стороны запрос, где мы указываем страницу

GET /blogs/page/6    -- good practice

number (или id) не требует обработки какого-либо состояния на стороне сервера и считается хорошей практикой.

Другой проблемой, которая может возникнуть в этом контексте, является кэширование. Использование кэша на стороне сервера может значительно ускорить обработку запросов. Однако следует заметить, что кэширование не означает, что сервер сохраняет состояние приложения. Он просто копирует данные для предыдущих запросов и помещает их в оперативную память, к которой можно получить доступ в случае будущих запросов.

Архитектурные ограничения

Итак, наконец, давайте рассмотрим шесть принципов проектирования REST. Вы заметите, что мы уже рассмотрели здесь несколько моментов.

1. Единый интерфейс

Все запросы API для одного и того же ресурса должны выглядеть одинаково, независимо от того, откуда поступает запрос. REST API должен гарантировать, что одна и та же часть данных, например имя или адрес электронной почты пользователя, принадлежит только одному универсальному идентификатору ресурса (URI). Ресурсы не должны быть слишком большими, но должны содержать всю информацию, которая может понадобиться клиенту.

2. Развязка клиент-сервер

В дизайне REST API клиентские и серверные приложения должны быть полностью независимы друг от друга. Единственная информация, которую должно знать клиентское приложение, — это URI запрошенного ресурса; никаким другим образом он не может взаимодействовать с серверным приложением. Точно так же серверное приложение не должно изменять клиентское приложение, кроме как передавать ему запрошенные данные через HTTP.

3. Безгражданство

API-интерфейсы REST не имеют состояния, а это означает, что каждый запрос должен включать всю информацию, необходимую для его обработки. Другими словами, REST API не требуют сеансов на стороне сервера. Серверным приложениям не разрешено хранить какие-либо данные, связанные с запросом клиента.

4. Кэшируемость

Когда это возможно, ресурсы должны кэшироваться на стороне клиента или сервера. Ответы сервера также должны содержать информацию о том, разрешено ли кэширование доставленного ресурса. Цель состоит в том, чтобы повысить производительность на стороне клиента и повысить масштабируемость на стороне сервера.

5. Многоуровневая системная архитектура

В REST API вызовы и ответы проходят через разные уровни. Как правило, не предполагайте, что клиентское и серверное приложения подключаются друг к другу напрямую.

В коммуникационном цикле может быть несколько различных посредников, каждый из которых несет определенную ответственность. Хороший дизайн гарантирует, что слои изолированы, не взаимодействуют с другими слоями, кроме тех, которые находятся под ними.

6. Код по запросу (необязательно)

REST API обычно отправляют статические ресурсы, но в некоторых случаях ответы могут также содержать исполняемый код (например, апплеты Java). В этих случаях код должен выполняться только по запросу.

Другие лучшие практики

Мы уже обсуждали следующие передовые практики в предыдущих абзацах — принимать и отвечать с помощью JSON, использовать существительные вместо глаголов в путях к конечным точкам, коллекции имен с существительными во множественном числе, вложенные ресурсы для иерархических объектов и кеширование данных для повышения производительности.

Есть несколько других вещей, о которых вы можете позаботиться. Это вещи, которые не нарушают принципы как таковые, но необходимы для хорошего дизайна API.

Изящно обрабатывать ошибки и возвращать стандартные коды ошибок

Чтобы избежать путаницы для пользователей API при возникновении ошибки, мы должны корректно обрабатывать ошибки и возвращать коды ответов HTTP, которые указывают, какой тип ошибки произошел. Некоторые распространенные коды состояния HTTP ошибок можно найти здесь.

Коды ошибок должны сопровождаться сообщениями, чтобы у сопровождающих было достаточно информации для устранения проблемы, но злоумышленники не могут использовать содержимое ошибки для проведения наших атак, таких как кража информации или сбой системы.

Разрешить фильтрацию, сортировку и разбиение на страницы

Базы данных REST API могут быть очень большими. Иногда данных так много, что их не следует возвращать сразу, потому что они слишком медленные или могут вывести из строя наши системы. Поэтому нам нужны способы фильтрации элементов.

Нам также нужны способы разбиения данных на страницы, чтобы мы возвращали только несколько результатов за раз. Мы не хотим слишком долго связывать ресурсы, пытаясь получить все запрошенные данные сразу. Сортировка помогает извлекать упорядоченные данные в соответствии с требованиями.

Надлежащие методы обеспечения безопасности

Большая часть связи между клиентом и сервером должна быть конфиденциальной, поскольку мы часто отправляем и получаем личную информацию. Поэтому использование SSL/TLS для обеспечения безопасности является обязательным.

SSL-сертификат не так уж сложно загрузить на сервер, и его стоимость либо бесплатна, либо очень низка. Нет никаких причин не использовать наши REST API для обмена данными по защищенным каналам, а не по открытым.

Версии наших API

У нас должны быть разные версии API, если мы вносим в них какие-либо изменения, которые могут нарушить работу клиентов. Управление версиями может быть выполнено в соответствии с семантической версией (например, 2.0.6 для обозначения основной версии 2 и шестого исправления), как это делают большинство приложений в настоящее время. Подробнее об этом можно прочитать здесь.

Таким образом, мы можем постепенно отказываться от старых конечных точек вместо того, чтобы заставлять всех одновременно переходить на новый API. Конечная точка версии 1 может оставаться активной для тех, кто не хочет меняться, в то время как версия 2 с ее блестящими новыми функциями может обслуживать тех, кто готов к обновлению. Это особенно важно, если наш API общедоступен. Мы должны верифицировать их, чтобы не нарушить работу сторонних приложений, использующих наши API.

Управление версиями обычно выполняется с добавлением /v1/, /v2/ и т. д. в начале пути к API.

Заключение (TL;DR)

Итак, вы готовы разрабатывать REST API как профессионал? 🙃

Давайте быстро резюмируем всю статью в следующих трех абзацах.

Наиболее важным выводом для разработки высококачественных API REST является согласованность с соблюдением веб-стандартов и соглашений. Коды состояния JSON, SSL/TLS и HTTP являются стандартными строительными блоками современной сети.

Производительность также является важным фактором. Мы можем увеличить его, не возвращая слишком много данных за один раз. Кроме того, мы можем использовать кэширование, чтобы нам не приходилось постоянно запрашивать данные.

Пути конечных точек должны быть согласованы. Мы используем только существительные, поскольку методы HTTP указывают на действие, которое мы хотим предпринять. Пути вложенных ресурсов должны идти после пути родительского ресурса. Они должны сообщать нам, что мы получаем или чем манипулируем, без необходимости читать дополнительную документацию, чтобы понять, что они делают.

Если вы прочитали это и нашли это полезным, вам также может понравиться —



Не стесняйтесь обращаться ко мне с любыми вопросами или предложениями, которые могут у вас возникнуть. Вы можете следить за мной в этих социальных сетях — LinkedIn, YouTube, Twitter, Instagram, чтобы получать больше обновленного контента!

Как всегда! Удачного взлома! 😇

Присоединяйтесь к моему списку адресов электронной почты, чтобы получать еще больше замечательных руководств и блогов по программированию ❤️