Использование HTTP сервисов, JSON и OpenAI в 1с

Тестовое задание разработчика 1С при устройстве на работу

Мой знакомый устраивается в крупный российский маркетплейс, после прохождения сотрудника отдела персонала, его попросили сделать тестовое задание с условием уложится в 2 часа.

Разберем задание и попробуем его решить.

Постановка задачи

Разработать и прислать рабочее расширение с HTTP-сервисом для постраничного получения номенклатуры. Ответить на вопросы по решению.

Требования уровень 1:

  • Параметры запроса: номер страницы, количество элементов на странице.
  • Формат возвращаемых данных: JSON.
  • Состав данных: ГУИД, Наименование, Единица измерения (наименование).

Требования уровень 2:

  • Авторизация в сервисе производится по JWT-токену (валидация токена не требуется, может быть произвольным).
  • Реализовать возвращаемые коды ошибок:
    • 401 – ошибка авторизации (токен не указан);
    • 404 – отсутствует страница.

Требования уровень 3: Подготовить и прислать спецификацию в формате OpenAPI.

Пример:

Запрос: http://localhost/demo/hs/nom/v1?p=4&c=10

Ответ:

[
   {
      "uid":"51f45cb4-1359-44as-9a6d-f058142eefa6",
      "name":"Стол",
      "unit":"шт"
   },
   {
      "uid":"e399d117-44cb-4c52-966d-0c8c6b93bf3f",
      "name":"Стул",
      "unit":"шт"
   }
]

Решение

Если захотим тестировать http-сервис не забываем настроить веб-сервер.

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

Решаем требование 1

Создаем HTTP-сервис «ПолучитьНоменклатуру» с корневым url «nom»

Создание HTTP-сервиса в 1с
HTTP-сервис 1с который возвращает номенклатуру

добавляем шаблон url и метод get

Создание методов http-сервиса 1с
http-сервис 1с шаблон url
Создание обработчика методов http-сервиса 1с
Метод get

Пишем код

Функция v1_МетодGet(Запрос)
	// Создаем запрос который вернет нам список номенклатуры по параметрам
	тЗапрос = Новый Запрос("ВЫБРАТЬ
	|	Номенклатура.Наименование КАК name,
	|	Номенклатура.ЕдиницаИзмерения КАК unit,
	|	Номенклатура.Ссылка КАК Ссылка,
	|	АВТОНОМЕРЗАПИСИ() КАК НомерЗаписи
	|ПОМЕСТИТЬ ВТ_ВсяНоменклатураСНомерами
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ ПЕРВЫЕ _&КоличествоНаСтранице_
	|	ВТ_ВсяНоменклатураСНомерами.name КАК name,
	|	ВТ_ВсяНоменклатураСНомерами.unit КАК unit,
	|	ВТ_ВсяНоменклатураСНомерами.Ссылка КАК Ссылка
	|ИЗ
	|	ВТ_ВсяНоменклатураСНомерами КАК ВТ_ВсяНоменклатураСНомерами
	|	ВТ_ВсяНоменклатураСНомерами.НомерЗаписи >= &Страница
	|
	|УПОРЯДОЧИТЬ ПО
	|	ВТ_ВсяНоменклатураСНомерами.НомерЗаписи");
	
    Запрос.Текст = СтрЗаменить(Запрос.Текст,"_&КоличествоНаСтранице_",Запрос.ПараметрыЗапроса["c"]);                       
	Запрос.УстановитьПараметр("Страница",Запрос.ПараметрыЗапроса["p"] * Запрос.ПараметрыЗапроса["c"]);	// номер страницы 
                           
	РезультатЗапроса = тЗапрос.Выполнить();
	
	МассивВозврата = Новый Массив;
	
	Если РезультатЗапроса.Пустой() Тогда
		// В ТЗ ничего нет про случай когда по параметрам ничего не нашлось
		// в этом случае вернем пустой массив
	Иначе
		Выборка = РезультатЗапроса.Выбрать();
		
		Пока Выборка.Следующий() Цикл
			// Собираем данные для возврата
			СтрокаСтруктура	= Новый Структура("uid,name,unit");
			ЗаполнитьЗначенияСвойств(СтрокаСтруктура,Выборка);
			СтрокаСтруктура.uid = XMLСтрока(Выборка.Ссылка);	
			МассивВозврата.Добавить(СтрокаСтруктура);	
		КонецЦикла;
	КонецЕсли;	
	
	// Переводим нужные данные в формат JSON
	ЗаписьJSON = Новый ЗаписьJSON;
	ЗаписьJSON.УстановитьСтроку();  
	ЗаписатьJSON(ЗаписьJSON, МассивВозврата);            
	JSONСтрока = ЗаписьJSON.Закрыть();
	
	// Формируем ответ
	Ответ = Новый HTTPСервисОтвет(200);
	Ответ.Заголовки.Вставить("Content-Type", "text/html; charset=utf-8");
	Ответ.УстановитьТелоИзСтроки(JSONСтрока);
	
	Возврат Ответ;
КонецФункции

Проверяем себя и выполняем запрос.

Результат работы HTTP-сервиса 1с
Результат запроса к http-сервису получения номенклатуры

Отлично, требование 1 выполнено, потрачено около 15 минут.

Переходим ко второй части, реализация авторизации по JWT-токену, если нам повезло и уже настало 8.3.21, то просто используем новый функционал 1с.

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

Функция v1_МетодGet(Запрос)
	// Авторизация по JWT-токену
	Токен = Запрос.Заголовки.Получить("Authorization");
	КодОтвета = 200;
	
	КоличествоНаСтранице	= Запрос.ПараметрыЗапроса["c"];
	Страница				= Запрос.ПараметрыЗапроса["p"];
	
	Если Токен = Неопределено Тогда
		КодОтвета = 401;
		ДанныеДляВозврата = НСтр("ru = 'ошибка авторизации (токен не указан)'");
	ИначеЕсли СтраницаНеСуществует(Страница,КоличествоНаСтранице) Тогда
		КодОтвета = 404;
		ДанныеДляВозврата = НСтр("ru = 'отсутствует страница'");
	Иначе
		ДанныеДляВозврата	= СобратьНоменклатурыПоПараметрам(Страница,КоличествоНаСтранице);				
	КонецЕсли;				
	
	JSONСтрока		= СформироватьJSONСтроку(ДанныеДляВозврата);
	Ответ	= СформироватьОтвет(КодОтвета,JSONСтрока);	
	
	Возврат Ответ;
КонецФункции

Функция СформироватьJSONСтроку(ВходныеДанные)
	// Переводим нужные данные в формат JSON
	ЗаписьJSON = Новый ЗаписьJSON;
	ЗаписьJSON.УстановитьСтроку();  
	ЗаписатьJSON(ЗаписьJSON, ВходныеДанные);            
	JSONСтрока = ЗаписьJSON.Закрыть();
	
	Возврат JSONСтрока;
КонецФункции

Функция СформироватьОтвет(КодОтвета,JSONСтрока)
	// Формируем ответ
	Ответ = Новый HTTPСервисОтвет(КодОтвета);
	Ответ.Заголовки.Вставить("Content-Type", "text/html; charset=utf-8");
	Ответ.УстановитьТелоИзСтроки(JSONСтрока);
	
	Возврат Ответ;
КонецФункции

Функция СобратьНоменклатурыПоПараметрам(p,c) 
	// Создаем запрос который вернет нам список номенклатуры по параметрам
	Запрос = Новый Запрос("ВЫБРАТЬ
	|	Номенклатура.Наименование КАК name,
	|	Номенклатура.ЕдиницаИзмерения КАК unit,
	|	Номенклатура.Ссылка КАК Ссылка,
	|	АВТОНОМЕРЗАПИСИ() КАК НомерЗаписи
	|ПОМЕСТИТЬ ВТ_ВсяНоменклатураСНомерами
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ ПЕРВЫЕ _&КоличествоНаСтранице_
	|	ВТ_ВсяНоменклатураСНомерами.name КАК name,
	|	ВТ_ВсяНоменклатураСНомерами.unit КАК unit,
	|	ВТ_ВсяНоменклатураСНомерами.Ссылка КАК Ссылка
	|ИЗ
	|	ВТ_ВсяНоменклатураСНомерами КАК ВТ_ВсяНоменклатураСНомерами
	|ГДЕ
	|	ВТ_ВсяНоменклатураСНомерами.НомерЗаписи >= &Страница
	|
	|УПОРЯДОЧИТЬ ПО
	|	ВТ_ВсяНоменклатураСНомерами.НомерЗаписи");
	 	
	Запрос.Текст = СтрЗаменить(Запрос.Текст,"_&КоличествоНаСтранице_",с);
    Запрос.УстановитьПараметр("Страница",p*c);	// номер страницы
	
	РезультатЗапроса = Запрос.Выполнить();
	
	МассивВозврата = Новый Массив;
	
	Если РезультатЗапроса.Пустой() Тогда
		// В ТЗ ничего нет про случай когда по параметрам ничего не нашлось
		// в этом случае вернем пустой массив
	Иначе
		Выборка = РезультатЗапроса.Выбрать();
		
		Пока Выборка.Следующий() Цикл
			// Собираем данные для возврата
			СтрокаСтруктура	= Новый Структура("uid,name,unit");
			ЗаполнитьЗначенияСвойств(СтрокаСтруктура,Выборка);
			СтрокаСтруктура.uid = XMLСтрока(Выборка.Ссылка);	
			МассивВозврата.Добавить(СтрокаСтруктура);	
		КонецЦикла;
	КонецЕсли;
	
	Возврат МассивВозврата;
КонецФункции

Функция СтраницаНеСуществует(Страница,КоличествоНаСтранице)
	Запрос = Новый Запрос("ВЫБРАТЬ
	|	Номенклатура.Ссылка КАК Ссылка,
	|	АВТОНОМЕРЗАПИСИ() КАК НомерЗаписи
	|ПОМЕСТИТЬ ВТ_ВсяНоменклатураСНомерами
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура
	|ГДЕ
	|	Номенклатура.Страница = &Страница
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ВТ_ВсяНоменклатураСНомерами.Ссылка КАК Ссылка
	|ИЗ
	|	ВТ_ВсяНоменклатураСНомерами КАК ВТ_ВсяНоменклатураСНомерами
	|ГДЕ
	|	ВТ_ВсяНоменклатураСНомерами.НомерЗаписи >= &Страница");
	Запрос.УстановитьПараметр("Страница",Страница*КоличествоНаСтранице);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если РезультатЗапроса.Пустой() Тогда
		Возврат Истина;
	Иначе
		Возврат Ложь;
	КонецЕсли;
КонецФункции

Вот и ещё около 30 минут потрачено, переходим к требованию 3.

Что бы выполнить требование три нужно разобраться что такое OpenAI и познакомится со swagger

Заходим в swagger и пишем там описание, какой-то автоматизации этого процесса из 1с я не знаю.

Полученный результат можно посмотреть по ссылке описание api

Интерфейс swagger и предварительный результат полученного описания API
swagger описание api в формате openAI

На этом все, критика приветствуется.


от

Комментарии

2 комментария на ««Тестовое задание разработчика 1С при устройстве на работу»»

  1. Аватар пользователя Владимир
    Владимир

    Здравствуйте!
    Я ищу примеры с использованием АВТОНОМЕРЗАПИСИ(). Вот нашел Вашу разработку.
    Не совсем понятно, для чего использовано АВТОНОМЕРЗАПИСИ().
    Откуда уверенность, что эта автонумерация всегда будет «одинаковой» для каждого запроса, т.е. то, что элементы всегда будут идти в одинаковой последовательности каждый раз?
    Почему просто не использовать упорядочивание по Коду или Ссылке и каким-то там образом разбивать это на страницы?

    Вот тут нет ошибки? У номенклатуры есть такой реквизит или Вы его добавили?
    |ГДЕ
    | Номенклатура.Страница = &Страница
    |;

    1. Аватар пользователя CrazyElephant_x

      Владимир, добрый день. АВТОНОМЕРЗАПИСИ() каждый раз присваивает случайное значение и это решение очень плохое.
      Когда я его делал не знал про пагинацию и как правильно с ней работать.

      Номенклатура.Страница = &Страница — тут я добавил реквизит, но это ужасное решение, так не делайте

      Постараюсь найти время и решить эту задачу нормально

Добавить комментарий