Выразительный Web API

27.04.20

Интеграция - WEB-интеграция

Теория разработки Web API с ожидаемым поведением, за который не будет стыдно за пределами мира 1С.

Введение

Что такое API?

Термины URI, URL, URN

HTTP-протокол

HTTP-запрос

HTTP-ответ

Методы запросов

Идемпотентность?!

Версионирование

Best practices

REST

Примеры конкретных URI

Введение

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

Что такое API?

Есть хороший пример идеального API не из мира IT и это ресторан. Если вы идете в ресторан как гость, то вам запрещено проходить на кухню. В этом случае вы должны знать, что вы можете заказать. Для этого у вас есть меню. После изучения меню, вы делаете заказ официанту, который передает заказ на кухню, и он же принесет вам то, что вы заказали. Официант может принести только то, что может дать ему кухня. Как же это относится к API? Официант это API ресторана. Вы пользователь API. Меню это документация, которая объясняет, что вы можете запросить у API. Блюдо в вашем заказе это запрос. Кухня это сервер, которая знает, как готовить то или иное блюдо.

Стоит заметить, что API это не только про Web. Например, все экспортные методы общего модуля или модуля менеджера документа - это тоже API.

Термины URI, URL, URN

  • URI - Uniform Resource Identifier (унифицированный идентификатор ресурса). Обозначает имя и адрес ресурса в сети. Как правило, делится на URL и URN.
  • URL - Uniform Resource Locator (унифицированный определитель местонахождения ресурса). Адрес некоторого ресурса в веб. URL определяет местонахождение ресурса и способ обращения к нему.
  • URN - Unifrorm Resource Name (унифицированное имя ресурса). Хороший пример это ISBN у книг (например, ISBN 978-5-699-12014-7 однозначно идентифицирует книгу, но ничего не говорит о ее местоположении). Смысл URN в том, что он определяет только название конкретного предмета, который может находится во множестве конкретных мест.

Можно сказать, что 

URI = URL + URN 

Приведу простой пример как это может выглядит на практике:

  • URI - https://mydomain.com/products.html
  • URL - https://mydomain.com
  • URN - /products.html

Еще пример структуры URI в виде картинки:

Протокол HTTP

HTTP - текстовый протокол передачи данных, который работает по схеме запрос-ответ (клиент-сервер). На данный момент является основным протоколом в Интернете. Поверх него часто делают прикладные протоколы (SOAP, WebDAV). Актуальная версия 1.1.

HTTP-запрос

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

Общий вид запроса

Метод Путь HTTP/Версия протокола

Host: Адрес

Другие заголовки (опционально)

(пустая строка)

Тело запроса (опционально)

Минимальный GET запрос

GET /wiki/HTTP HTTP/1.1

Host: ru.wikipedia.org

HTTP-ответ

Используется для отправки сервером клиенту запрошенных данных. Формат ответа - текстовый.

Общий вид ответа

HTTP/Версия протокола Код статуса/Текст статуса

Заголовки

(пустая строка)

Тело ответа (опционально)

Пример ответа сервера

HTTP/1.1 200 OK

Content-Type: text/html; charset=utf-8 Content-Length: 512

(пустая строка)

(тело ответа)

Методы запросов

Для каждого запроса обязательным является указание метода. Рассмотрим самые популярные методы в контексте CRUD операций. Если говорить о SQL, то вы не сможете оператором select удалить данные, а оператором update вставить новые. Что касается методов HTTP-запросов, то технически такого ограничения нет. Если вы разрабатываете веб-сервис, то можете сделать так, что любым методом можно получить данные или удалить. Но так делать крайне не рекомендуется, потому что это будет неожиданное поведение сервиса, да и в принципе для этих операций есть свои методы. 

Распространенные методы

  • GET - получение содержимого указанного ресурса (Retrieve в контексте CRUD).
  • POST - передача данных или для операции Create в контексте CRUD.
  • PUT - изменение данных ресурса целиком (операция Update в контексте CRUD).
  • DELETE - удаление указанного ресурса (Delete в контексте  CRUD).
  • PATCH - частичное изменение ресурса (применяется не часто, обычно используется PUT)
  • HEAD - практически тоже самое, что GET, но без тела ответа. Можно использовать как валидацию URL через кастомный заголовок в ответе.

Если веб сервис разрабатывается для работы с формами HTML, то можно использовать только методы GET, POST. Но для поддержки остальных достаточно использовать JS. Если говорить не про формы, то в любом современном ЯП есть поддержка остальных методов "из коробки".

Идемпотентность

Выдыхайте, это про методы запросов. Запрос является идемпотентным, если повторный идентичный запрос, сделанный с его помощью, гарантирует одинаковое воздействие на систему, при этом возвращаемые ответами коды статусов могут быть различными. Другими словами, идемпотентный метод не должен иметь никаких побочных эффектов (side-effects).

Идемпотентные методы

  • GET, HEAD - независимо от того, сколько будет раз запрошен ресурс, состояние системы никак не меняется.
  • PUT, PATH - состояние ресурса при идентичных запросах будет изменено только в первый раз (ресурс с id=0 имел имя name0, после первого изменения имя стало name1, но и при последующих запросах оно вновь будет name1).
  • DELETE - удалить ресурс с помощью идентичных запросов можно также только один раз.

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

Не идемпотентные методы

  • POST - независимо от того, сколько раз мы передадим данные, они будут добавлены (не берем в расчет контроль уникальности реквизитов), то есть состояние системы меняется при каждом запросе.

Почему идемпотентность важна? Это соглашение. То есть это то, на что пользователи будут рассчитывать при работе с вашим сервером.

Версионирование

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

  • URL - {host}/v1/products
  • Custom header - api-version:1

Best practices

Поделюсь списком лучших практик, которые использую в своей работе:

  • Никакой кириллицы при именовании ресурсов. Иначе адрес придется кодировать и при интеграции со сторонними системами никто вам спасибо за такое не скажет.
  • В модуле http-сервиса только логика работы с объектом HTTPRequest. Вся бизнес-логика должна быть вынесена в общий модуль. Так вы получите независимые слои приложения (с натяжкой сюда можно прикрутить термин MVC) и простоту тестирования бизнес-логики.
  • Методы POST и PUT должны отдавать соответственно созданный и измененный объекты обратно. Этим вы избавите клиента от повторного вызова вашего сервиса.
  • Поддержка обработки заголовка Content-Type. Например, если заголовок не указан - сервис отдает ответ в формате json, а если указан application/xml - то ответ в xml.
  • Стандартные коды статусов ответов. Например, код 415 используйте тогда, когда клиент запрашивает ответ в формате xml, а вы его не поддерживаете. В противном случае поведение придется описывать в документации.
  • Pretty print для сериализованных данных. Экономия на символах табуляции дает не так много, зато убивает читаемость ответа при отладке. 
  • Если на сервере опубликован не только ваш веб-сервис, а допустим веб-клиент, то необходимо разделение таких ресурсов через URI. Обычно, сервис начинается с /api/.... В нашем случае платформа за нас добавляет /hs. Так что этот пункт не обязателен, но помнить про него нужно. 

REST

REST (Representational State Transfer — «передача состояния представления»). Не является протоколом, но описывает набор архитектурных принципов формирования API.

Основные идеи REST

  • Клиент-серверная архитектура.
  • Все есть ресурс.
  • Любой ресурс имеет ID (путь из URI).
  • Сервер не хранит никакого состояния, то есть все обработчики stateless. Вся информация, которая необходима для обработки запроса, передается клиентом вместе с запросом.
  • Список доступных действий определяется стандартными методами HTTP.

В связи с недавней популярностью этой аббревиатуры, многие ее смысл понимали как что угодно, лишь бы это было связано с формированием Web API. На самом деле, это правила формирования URI. В качестве примера можно привести структуру папок на диске и доступные операции с ними. Допустим есть папка D:/files и есть файл Dummy.data. Если необходимо получить содержимое файла, то используется D:/files/dummy.data. Если нужно изменить файл, то опять же D:/files/dummy.data. Если нужны все файлы из это папки, то D:/files. При любой операции с файлами остается неизменным путь к папке. Именно такой подход используется в REST.

Но такой подход далеко не всегда удобен. Например, если вы пишете сервис для обмена с другой ИС на платформе 1С и в обоих случаях используются планы обмена, то REST здесь вряд ли подойдет, потому что клиент в теле запроса присылает целую пачку данных и скорей всего ваш сервис будет состоять из 1-2 методов. Ранее я освещал эту тему - Обмен без правил.

Примеры конкретных URI

Рассмотрим конкретный пример сервиса для работы с товарами.

Действие Метод URI
Получить список всех товаров GET /products
Получить список всех товаров марки NoName и классом продукта A  GET /products?brand=NoName&class=A
Получить определенный товар (id=0) GET /products/0
Добавить товар POST /products
Изменить товар PUT

/products/0

Удалить товар DELETE /products/0

 

Примеры неправильных URI

  • /products/getAll
  • /products/brand/NoName
  • /products/?action=put&id=0
  • /products/delete/?id=0
 
 Пример того, как такой сервис может выглядеть на уровне метаданных 1С

REST API HTTP-сервис Архитектура

См. также

Интеграция Альфа Авто 5 / Альфа Авто 6 и AUTOCRM / Инфотек

Сайты и интернет-магазины WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме. Без существенных изменений типовой конфигурации. Проверено с брендами: Интеграция 1С и GEELY Интеграция 1С и HAVAL Интеграция 1С и KIA Интеграция 1С и FORD Интеграция 1С и LADA ГАРАНТИЯ 100% ВНЕДРЕНИЯ!

36000 руб.

03.08.2020    15393    9    16    

7

Модуль для обмена "1С:Предприятие 8. УАТ. ПРОФ" с FortMonitor

WEB-интеграция 8.3.8 Конфигурации 1cv8 Автомобили, автосервисы Беларусь Украина Россия Казахстан Управленческий учет Платные (руб)

Расширение предназначено для конфигурации "1С:Предприятие 8. Управление Автотранспортом. ПРОФ". Функционал модуля: 1. Заполнение регистров сведений по подсистеме "Мониторинг", а именно: события по мониторингу, координаты по мониторингу, пробег и расход по мониторингу, текущее местоположение ТС по мониторингу 2. Заполнение путевого листа: пробег по мониторингу, время выезда/заезда, табличная часть ГСМ, места стоянок по геозонам. 3. Отчеты по данным загруженным в регистры сведений. 4. Предусмотрена автоматическая загрузка данных в фоновом режиме (условия работы данной загрузке читайте в описании товара) Модуль работает без включенной константы по настройкам мониторинга. Модуль формы предоставляется с открытым кодом, общий модуль защищен. Любой заинтересованный пользователь, имеет возможность скачать демо-версию расширения.

22656 руб.

25.05.2021    12713    30    7    

10

[Расширение] БОР-Навигатор.Культура

Зарплата Бюджетный учет WEB-интеграция Обмен с ГосИС Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бюджетный учет Платные (руб)

Расширение конфигурации, включающее в себя объекты, необходимые для подготовки и сдачи отчета "Штатная численность" системы "БОР-Навигатор.Культура" в программе "1С:Зарплата и кадры государственного учреждения", редакция 3.1.

8400 руб.

01.02.2019    25564    9    0    

7

Интеграция с сервисом vetmanager

WEB-интеграция Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    15907    41    49    

22

Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС

Обмен с ГосИС WEB-интеграция Платформа 1С v8.3 Управляемые формы 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия государственного учреждения 1С:Документооборот 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Платные (руб)

Обработка является альтернативой механизму, разработанному фирмой 1С и заполняющему реквизиты контрагента по ИНН или наименованию. Не требуется действующей подписки ИТС. Вызывается как внешняя дополнительная обработка, т.е. используется, непосредственно, из карточки контрагента. Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС (egrul.nalog.ru) для БП 2.0, БП 3.0, БГУ 1.0, БГУ 2.0, УТ 10.3, УТ 11.x, КА 1.1, КА 2.x, УПП 1.x, ERP 2.x, УНФ 1.5, УНФ 1.6, УНФ 3.0, ДО 2.1

2400 руб.

28.04.2016    87810    157    215    

314
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. CyberCerber 848 27.04.20 17:34 Сейчас в теме
Полезная статья, спасибо!
Буквально месяц - два назад сам искал best practices, правила написания хорошего API.
Ты рассказал про общие методы: создание, изменение объекта...
А как правильно реализовать, например, поиск объектов по фильтрам? Это будет GET или POST? Что стоит делать параметрами url, а что помещать в тело запроса?
nekit_rdx; +1 Ответить
2. nbeliaev 823 27.04.20 17:43 Сейчас в теме
(1) Спасибо за отзыв )
В разделе Примеры конкретных URI есть инфо как реализовать поиск по фильтрам и как его не надо делать (если быть точным то вот это /products?brand=NoName&class=A).
3. CyberCerber 848 27.04.20 17:55 Сейчас в теме
(2) А если нужно передать фильтры по сложнее? Например, найти товары:
1. В списке категорий: Телефоны, Планшеты, Часы
2. Имя содержит "самое лучшее устройство *&^%$#* !"
3. Страна производства не равна Китай
4. nbeliaev 823 27.04.20 18:02 Сейчас в теме
(3) Я бы все делал через параметры запроса, они специально для этого и заточены. То есть так как это все же получение данных, то метод GET, а в нем тела нет. Другой вопрос, что может немного придется распарсить такие параметры уже на стороне сервера.
6. CyberCerber 848 27.04.20 22:06 Сейчас в теме
(4) В общем случае, фильтры могут быть представлены произвольным JSONом. Нормально передавать JSON параметром URLа?
7. nbeliaev 823 28.04.20 05:36 Сейчас в теме
(6) Скорей всего придется кодировать такую строку из за спец. символов в json. А нормально ли передавать или нет, точного ответа я не могу дать, не сталкивался ни разу. Но сам бы я подумал хорошо еще раз перед тем как использовать такой подход.
8. ltfriend 933 28.04.20 09:19 Сейчас в теме
(6) конечно, идеологически для возврата результатов поиска больше подходит GET. Вы данные получаете, а не добавляете, изменяете или удаляете. Но если вы используете сложные параметры (фильтры), то разумней сделать POST с JSON'ом в теле. Это не является криминалом. А общие рекомендации не являются обязательными к исполнению и вполне могут быть исключения. И не стоит забывать, что передавая кучу сложных параметров в URL вы можете превысить его максимально допустимую длину.
9. nbeliaev 823 28.04.20 09:23 Сейчас в теме
(8) Согласен, что это всего лишь рекомендации и про длину вы верно подметили. Все зависит от конкретного кейса. Поэтому я и написал, что надо подумать.
Но в общем случае все же GET предпочтительнее )
10. ltfriend 933 28.04.20 09:25 Сейчас в теме
(9) в общем случае конечно. Но бывают частные, в которых как раз и можно отойти от общих рекомендаций.
11. CyberCerber 848 28.04.20 09:57 Сейчас в теме
(8) Да, вот у меня поэтому и был вопрос, т.к. частенько я встречаю API, где получение данных проходит через POST, т.к. в теле передается полноценный JSON.
12. nomad_irk 68 28.04.20 10:07 Сейчас в теме
(11)ИМХО, тут работает такое же правило, как и везде: если параметров у процедуры/функции можно пересчитать по пальцам одной руки, то их МОЖНО запихать в строку запроса GET, если больше - делай полноценный POST с блэкджеком и прочей атрибуикой......
5. nicxxx 253 27.04.20 18:30 Сейчас в теме
(1) Посмотрите документацию по интерфейсу oData, который 1С предоставляет по-умолчанию. Там есть про фильтры.
13. bulpi 214 28.04.20 12:09 Сейчас в теме
Единственный ИМХО сомнительный совет в статье :
"Методы POST и PUT должны отдавать соответственно созданный и измененный объекты обратно."
А если он там на фиг не нужен, зачем его отдавать?
14. nbeliaev 823 28.04.20 12:26 Сейчас в теме
(13) Спасибо за проявленный интерес.
Отдавать нужно, чтобы клиент мог проверить какие-то ключевые поля (например те, которые считаются на сервере). То есть ему не нужно дергать сервис еще раз через GET чтобы получить созданные/обновленные атрибуты сущности.
16. malikov_pro 1283 29.04.20 05:52 Сейчас в теме
(14) Зависит от варианта использования, если данные записаны некорректно, то это ошибка сервиса, о которой нужно сообщить клиенту.

У Вас указана структура метаданных, но она неудобна для обработки листенерами (предварительные проверки и аутентификация), мои наработки по теме https://infostart.ru/public/1131305/, буду рад разумной критике.

В статью можно добавить вариант обработки 404, потому что при if GET/{id} -> 404(POST) else (PUT/{id}) насоздавать дубликатов, а 404 может выдать и прокси. Вариант решения договоренность через документацию о формате тела ответа при ошибке.

С вопросом практики реализации имеет смысл связать вопрос документирования.
17. nbeliaev 823 29.04.20 07:33 Сейчас в теме
(16) Спасибо за комментарий.

аутентификация
- у нас есть Basic auth. Если этого не достаточно, то можно использовать токены в заголовках.

предварительные проверки
- про что именно вы говорите? Валидация запроса? Если да, то не упомянул этот момент в публкации, может есть смысл добавить.

404
- конечно нужно это делать и не только 404. В целом я упомянул про коды статусов, но расписывать не стал, так как нужен более конкретный пример для этого.
18. malikov_pro 1283 29.04.20 07:57 Сейчас в теме
(17)
"Basic auth" реализованная на уровне платформы привязана к пользователям в конфигураторе это не всегда удобно, как и подсистема БСП внешних пользователей.
В своих проектах использую справочник внешних пользователей и листенером для всех запросов делаю проверку.

"Валидация запроса?" - в общем да, проще проверить перед тем как отправлять данные в общий модуль (контроллер по сути).


"более конкретный пример для этого." - пример типа ресурса(формат RAML) во вложении, в основном блоке используется:
/categories:
  type: collection-item
  description: Работа со справочником категории (группы номенклатуры в 1С)
  /{xml_id}:
      type: item


Можно совместно продумать и сделать описание/реализацию основных функций по работе с объектами для 1С, аналог https://infostart.ru/public/709325/ только для сервера.
Прикрепленные файлы:
item.type.raml
15. hardcodder2020 28.04.20 13:11 Сейчас в теме
Статья полезная, спасибо, автор!
19. Vortigaunt 96 03.05.20 18:16 Сейчас в теме
В модуле http-сервиса только логика работы с объектом HTTPRequest. Вся бизнес-логика должна быть вынесена в общий модуль. Так вы получите независимые слои приложения (с натяжкой сюда можно прикрутить термин MVC) и простоту тестирования бизнес-логики.

Эта рекомендация важна не только ради красоты. Как оказалось, 1С не проверяет синтаксис в модуле http-сервиса. И чем меньше там будет кода, тем меньше нервов потратишь при отладке.
20. Cyberhawk 135 10.06.20 09:06 Сейчас в теме
Хорошо бы для каждого примера из раздела
Примеры неправильных URI
дать пояснение, что и почему там неправильно
21. nbeliaev 823 10.06.20 13:14 Сейчас в теме
(20)
Спасибо за интерес к материалу.
/products/getAll - REST оперирует глаголами, которые предоставляют методы HTTP. Здесь мы изобрели "свой" глагол
/products/brand/NoName - Попробуйте представить что будет, если кроме brand будет еще хотя бы 5 параметров. Для этого есть параметры запроса, а не части пути.
/products/?action=put&id=0 - Практически аналогично с первым пунктом, только здесь глагол как параметр запроса.
/products/delete/?id=0 - Практически аналогично с первым пунктом, только здесь глагол как часть пути.
22. Cyberhawk 135 10.06.20 13:24 Сейчас в теме
(21) Я не для себя спрашивал :)
Неплохо бы добавить эти пояснения в саму публикацию.
Оставьте свое сообщение