В этом руководстве вы узнаете, как объявить правила валидации параметров интеграции, когда Модуль интеграций проверяет каждое из них и как их протестировать.
Все правила из этого руководства объявляются в дескрипторе провайдера. Полный список полей параметра смотрите в справочнике Дескриптор провайдера интеграций.
Модуль проверяет параметры в два момента, и каждый раз в разном объёме:
Сохраняются настройки по секциям, поэтому конфигурация может быть корректной в каждой секции по отдельности и при этом неполной в целом. Такая интеграция получает статус Не завершено, и потребители не получат её параметры, пока администратор магазина не заполнит недостающее.
| Правило | При сохранении | Полная валидация |
|---|---|---|
| Встроенные правила типа параметра и | Только отправленные параметры | Все параметры |
| параметра | Только отправленные параметры | Все параметры |
| дескриптора | Никогда | Всегда |
Схема показывает оба прохода рядом и то, где рядом с ними стоит проверка соединения:
При сохранении каждый отправленный параметр проходит встроенное правило, а затем собственный , и любая проблема отклоняет сохранение с ошибкой . Полная валидация разбирает всю конфигурацию целиком и решает, завершена ли интеграция, но сохранение она не блокирует. Проверка соединения не относится ни к одному из проходов. Администратор магазина запускает её отдельным действием, и она вызывает дескриптора только с параметрами, которые удалось получить, то есть для включённой и полностью настроенной интеграции. Как её написать, читайте в руководстве Как создать провайдер Модуля интеграций.
У каждого типа параметра () есть свои правила, например формат URL для или допустимые значения для . Поля конкретного типа добавляют новые, например и для или , и для . Все они перечислены в разделе Дополнительные поля по типу параметра.
отклоняет параметр без значения. Для всех типов, кроме и , значением не считается пустая строка, а для всех типов ещё и . Параметр с никогда не нарушает , потому что пропуск заполняет значение по умолчанию.
Форма в Admin тоже отмечает обязательные поля и не отправляет их пустыми. Исключение составляет секрет, у которого уже есть сохранённое значение: пустое поле оставляет его как есть.
Для параметра типа правило про пустую строку не действует, потому что пустая строка для него значение. На сервере одного достаточно, чтобы принять , и интеграция считается полностью настроенной с пустым полем. Форма в Admin не даст отправить пустое обязательное поле, а запрос к API Admin или виджет даст. Добавьте обязательному параметру значение , чтобы отклонять такие значения, как это делает провайдер ЮKassa для своих и .
Если встроенных правил параметра недостаточно, добавьте ему функцию . Она получает значение параметра и контекст с двумя полями:
Например, код ставки НДС обязателен, только пока включены чеки:
providers/integration-my/services/my-integration.ts1import { defineIntegration } from "@gorgo/medusa-integration"2import type { OptionValidateContext } from "@gorgo/medusa-integration"34const requiredWhenReceipt = (value: number | undefined, ctx: OptionValidateContext) => {5 if (ctx.options.useReceipt && value == null) {6 ctx.addIssue({ message: "Required when receipts are enabled" })7 }8}910const descriptor = defineIntegration({11 category: "payment",12 displayName: "my.name",13 options: {14 apiKey: {15 type: "string",16 control: "secret",17 secret: true,18 required: true,19 minLength: 1,20 label: "my.apiKey"21 },22 useReceipt: {23 type: "boolean",24 default: false,25 label: "my.useReceipt"26 },27 vatCode: {28 type: "enum",29 values: [1, 2, 3, 4, 5, 6],30 label: "my.vatCode",31 visibleWhen: { field: "useReceipt", equals: true },32 validate: requiredWhenReceipt,33 },34 },35 sections: [36 {37 id: "credentials",38 title: "my.credentials",39 options: ["apiKey"]40 },41 {42 id: "receipts",43 title: "my.receipts",44 options: ["useReceipt", "vatCode"]45 },46 ],47})
не помечен , поэтому магазину, который не отправляет чеки, заполнять его не нужно. только прячет поле в Admin, пока выключен, а обязательным его делает . Правило читает из . Это конфигурация с наложенными отправленными значениями, поэтому правило видит переключатель независимо от того, сохраняется ли он вместе с .
Условное поле проверяйте в и не сочетайте с . Поле, скрытое через , всё равно отправляется и проверяется, потому что форма в Admin подставляет и отправляет все поля своей секции. Скрытый параметр типа , , , или без уходит пустым, не проходит , и модуль отклоняет сохранение, пока поле скрыто.
При сохранении правило параметра выполняется, только если этот параметр отправлен. Если бы находился в другой секции, его включение сохранилось бы без ошибок, а полная валидация оставила бы интеграцию в статусе Не завершено, пока администратор магазина не заполнит .
Правило, которое читает соседний параметр со , может видеть разные значения в двух проходах. Если этот параметр находится в секции, которая ещё не сохранена, при сохранении правило не найдёт его, а при полной валидации найдёт значение по умолчанию. Правило может пройти при сохранении, а интеграция останется в статусе Не завершено. Подставляйте значение по умолчанию соседнего параметра прямо в правиле, например для параметра с .
Правило, которое сравнивает несколько параметров и не относится ни к одному из них, задаётся в собственном дескриптора. Оно получает всю собранную конфигурацию и , который через может указать на любой параметр:
providers/integration-my/services/my-integration.ts1const descriptor = defineIntegration({2 // ...3 validate: (full, { addIssue }) => {4 if (full.mode === "webhook" && !full.webhookSecret) {5 addIssue({ path: ["webhookSecret"], message: "Required when mode is \"webhook\"" })6 }7 },8})
Это правило выполняется только при полной валидации. Секция с сохранится в любом случае, а интеграция останется в статусе Не завершено, пока правило сообщает о проблеме. Если правило на самом деле касается одного параметра, задайте его в этого параметра, чтобы администратор магазина узнал о проблеме при сохранении.
Сохранение, которое не прошло валидацию, возвращает ошибку , и Admin показывает её сообщение в уведомлении. В сообщении каждая проблема записана как , например .
Конфигурация, которая не проходит полную валидацию, получает статус Не завершено в списке и на странице интеграции. Проблемы полной валидации Admin не перечисляет, поэтому сообщения правил для нескольких секций пишите для разработчика, который тестирует дескриптор, а не для администратора магазина.
экспортирует полную валидацию самого модуля, поэтому unit-тест может проверить дескриптор без запущенного приложения Medusa:
Например, тест для дескриптора выше:
providers/integration-my/__tests__/descriptor.unit.spec.ts1import { collectValidationIssues } from "@gorgo/medusa-integration"2import MyIntegrationProvider from "../services/my-integration"34const descriptor = new MyIntegrationProvider().descriptor56describe("my integration descriptor", () => {7 it("requires a VAT code once receipts are on", () => {8 expect(9 collectValidationIssues(descriptor, { apiKey: "key", useReceipt: true })10 ).toEqual([11 { path: "vatCode", message: "Required when receipts are enabled" },12 ])13 })14})
выполняет те же проверки, что и модуль перед тем, как параметры станут активными. Он разбирает всю конфигурацию схемой дескриптора, которая за один проход подставляет значения по умолчанию и применяет встроенные правила, а затем выполняет каждого параметра и дескриптора. Если встроенное правило не прошло, собственные правила всё равно выполняются, но над исходной конфигурацией без значений по умолчанию, поэтому правило, которое читает соседний параметр со значением по умолчанию, не найдёт его. соединяет точками идентификатор параметра и вложенные ключи.