redb.Route 4.0: тест-кит, шаблоны payload, форматы данных, REST DSL и ядро без Newtonsoft

Восемь новых пакетов и REST DSL вокруг прежних 56 глаголов маршрута; из ядра ушёл Newtonsoft.Json. Что ломает мажор и как мигрировать за десять минут.
Готовится четвёртая версия redb.Route, интеграционного движка для .NET в духе Apache Camel. В 3.x была закрыта ширина по паттернам: 56 глаголов DSL, тридцать с лишним коннекторов, свой язык выражений, скомпилированный в IL (в 4.0 он качественно переработан, об этом ниже). 4.0 закрывает то, что вокруг паттернов: как протестировать маршрут без брокеров, как собрать тело сообщения, как читать CSV и Avro, как выставить REST-фасад, как кэшировать ответ сервиса. Восемь новых пакетов, REST DSL внутри HTTP-коннектора, переработанный язык выражений и ядро, которое стало легче, а не тяжелее. За год это первый мажор такого масштаба: не смена номера под несколько ломающих правок, а качественное расширение функционала, и ломающих изменений в нём как раз немного.
Что появилось
redb.Route.TestKit. Маршрут без брокеров и без правок в нём:AdviceRouteсReplaceFrom,MockEndpoints("kafka://*"),WeaveById; богатыйMockEndpointс ожиданиями и сценарными ответами;NotifyBuilder;ctx.SendBodyвместо связки эндпоинт/продюсер. Без зависимости на тестовый фреймворк.redb.Route.Templates. Тело из шаблона на Scriban:SetBodyTemplate("order.json.sbn", MediaType.Json, args). Тип результата обязателен и задаёт экранирование подставленных значений, шаблон компилируется приStart(), песочница без вызова методов, режим Liquid.redb.Route.DataFormats.Csv / Protobuf / Avro / Yamlплюс Base64, GZip и Zip в ядре. Каждый формат этоIMessageSerializer, так чтоMarshal("text/csv"),UnmarshalCsv<List<Row>>()и разбор поContentTypeсообщения работают через уже существующие узлы. У Protobuf и Avro есть обрамление Confluent.redb.Route.JsonTransform. JSON в JSON на JSONata с нативным .NET-движком:TransformJson("order-to-shipment.jsonata"), в спецификации доступны$headersи$properties.redb.Route.Cache. Кэш как EIP в двух формах над одним хранилищем: скоупCache(key, ttl)…EndCache()и компонентcache:region?action=get|put|remove|clear. В процессе черезIMemoryCache, распределённо через любойIDistributedCache.REST DSL в
redb.Route.Http.Rest("/api/orders").Get("/{id}").OutType<Order>().To(...),Consumes/Producesс 415, JSON-биндинг, OpenAPI 3.0.3 по адресу{basePath}/openapi.json. Поверх существующего консюмера и общего Kestrel-хоста.В ядре:
AggregationStrategies(одиннадцать готовых стратегий дляAggregate,Multicast,Split,Enrich),Enrichбез стратегии, keyed throttle с лимитом из сообщения,Intercept/InterceptFrom/InterceptSendToEndpointс сухим прогоном,OnCompletion,SetHeaders,RemoveHeaders(маска),Sort.
Пример из первого пункта, потому что с него обычно начинается знакомство:
await using var ctx = new RouteContext().AddRoutes(new OrdersRoutes());
ctx.AdviceRoute("orders", a => a
.ReplaceFrom("direct://test-in") // вместо kafka://orders
.MockEndpoints("kafka://*", "sql:*")); // каждый подходящий To(...) уходит в мок
await ctx.Start();
var vip = ctx.Mock("kafka://orders-vip").ExpectMessageCount(1).ExpectHeader("priority", "high");
await ctx.SendBodyAndHeader("direct://test-in", order, "priority", "high");
await vip.AssertIsSatisfiedAsync(TimeSpan.FromSeconds(2));
Кто писал такое на Camel, узнает adviceWith, mockEndpoints и mock:kafka:orders-vip. Это намеренно: там, где форма Camel верна, взяты и форма, и имена. Где разошлись, разобрано в полной статье.
Ядро стало легче
Из зависимостей redb.Route ушёл Newtonsoft.Json: jpath переехал на JsonPath.Net (RFC 9535) поверх System.Text.Json, и в ядре осталась одна JSON-модель на сериализатор, валидацию по схеме, jpath и форматы. Перед заменой диалект был снят снимком на 60 форм; 44 совпали байт в байт, 16 расхождений перечислены в changelog. Ни Scriban, ни CsvHelper, ни Google.Protobuf, ни Chr.Avro, ни YamlDotNet, ни Jsonata, ни абстракции кэширования в ядро не попали, каждая библиотека живёт в своём пакете.
Язык выражений
В 4.0 входит и переработанный язык выражений: одна грамматика и один компилятор для условий, значений и ${...}-шаблонов вместо трёх движков с несовпадающими дырами. Условие читается независимо от пробелов (header.amount>1000 больше не отбрасывает молча весь поток), битое условие или плейсхолдер роняют Start(), а не превращаются в константу на живом трафике, предикаты ждутся асинхронно, Validate и LoopWhile принимают строку. Второй, рукописный разборщик логики удалён целиком, около 800 строк. Поведение при этом меняется в трёх местах: одно правило истинности везде (ноль, "0", "no" и "off" теперь ложь), плейсхолдер на всю строку ${header.a} сохраняет CLR-тип значения, отсутствующее значение через Evaluate<string> даёт null, а не пустую строку. Всё закреплено сеткой характеризации на две с лишним сотни форм в трёх позициях. Разбор языка целиком выйдет отдельной статьёй вслед за релизом.
Что ломает мажор
Список короткий; кроме правила истинности, вся миграция механическая.
Было | Стало |
|---|---|
|
|
|
|
|
|
|
|
| ошибка при |
| строка остаётся строкой, числа инвариантно, |
| одно правило истинности: ноль и слова-отрицания ложь |
| плейсхолдер на всю строку отдаёт |
Перегрузки LoopExpression(IExpression, …), DelayExpression(IExpression) и ThrottleExpression(IExpression, period) остались: суффикс Expression во всём DSL означает «принимает IExpression», а строку принимает сам глагол, как Filter(string) принимал всегда. Пакеты, получавшие Newtonsoft транзитивно через redb.Route, добавляют собственную ссылку.
Как это будет ставиться
dotnet add package redb.Route
dotnet add package redb.Route.TestKit
dotnet add package redb.Route.Templates
dotnet add package redb.Route.DataFormats.Csv # Protobuf / Avro / Yaml по той же схеме
dotnet add package redb.Route.JsonTransform
dotnet add package redb.Route.Cache
dotnet add package redb.Route.Http # REST DSL внутри
Пакеты выйдут одной линией 4.0.0, 45 штук на одном номере, под net8.0, net9.0 и net10.0. Бесплатно, как и ядро. Полный разбор с примерами по каждому пакету, устройством под капотом и сравнением с Camel выйдет вместе с релизом, следом за ним отдельная статья про язык выражений. Исходники на github.com/redbase-app, пакеты на NuGet.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.