public class MyService {
private final DbClient dbClient;
public void doSomething(Request request) {
Long id = dbClient.getLastId();
dbClient.update(id, request);
}
}
public class DbClient {
public Long getLastId() {
//запрос в БД
}
public void update(Long id, Request request) {
//запрос в БД
}
}
public class MyServiceTest {
private MyService myService;
public void doSomethingTest() {
DbClient dbClient = mock(DbClient.class);
when(dbClient.getLastId()).thenReturn(1);
doNothing().when(dbClient.update(any(), any()));
Request request = createRequest();
myService.doSomething();
verify(dbClient).getLastId();
veryfy(dbClient).update(eq(1), eq(request));
}
}
пример очень простой, но для более сложных случаев разница будет лишь в количестве тестов и моков. поведение мокается в самом тестовом методе, и для разных случаев можно определить разное поведение.
если такая операция вызывается только извне, создаётся обработчик для неё (handler/operation), последовательно вызывающий шаги (service)
можно использовать движок бизнес-процессов, где "создание заявки на кредит" выделено в отдельный процесс, который можно переиспользовать. и вызываться он будет непосредственно движком БП.
если операция должна переиспользоваться в рамках приложения, можно сделать класс типа "сервис", который и будет фасадом. но в случае, если это какие-то крупные шаги, придётся всё-таки нарушить правило "сервис не вызывает сервис".
если данная операция может выполнятся асинхронно, можно реализовать отправку сообщения в рамках одного приложения, использовав либо внешний брокер, либо возможности языка/фреймворка, чтобы положить событие в какую-то внутреннюю очередь. дальнейшая обработка согласно п. 1.
у меня на одной руке longines, чтобы смотреть дату-время (а ещё они красивые), а на другой браслет xiaomi с будильником и прочими уведомлениями. удобно.
у спецификации asyncApi есть особенность - там описываются параметры и запросов и ответов, а также топики/очереди, куда они кладутся (или откуда берутся). этим она принципиально отличается от openApi.
Отчасти с вами согласен, в массиве ошибок ошибки пишутся в произвольном формате, который схемой не задаётся. На нашем проекте о нём мы просто договорились. На бэке он генерится
Однако, если в email пришёл null, то это и есть null, т.к. в противном случае пришла бы ошибка.
Минусом же можно отметить необходимость в реализации как схемы, так и кода — это может занимать чуть больше времени при разработке API + теперь появляется 2 источника, которые обязаны не конфликтовать друг с другом и быть полностью синхронизированы - лишнее звено, которое может поломаться.
Можно генерить код из схемы, тогда конфликтов не будет, а вам не придётся писать лишний код. Мы используем для генерации graphql-java-codegen. Он позволяет генерить как DTO, так и интерфейсы API, которые потом можно реализовать, используя ваш любимый фрейсворк.
Сейчас это не реализовано, но можно где-то в БД держать список полей, доступных роли. При запросе к API Gateway можно сравнить запрашиваемые поля с доступными и, в случае если запрошено что-то лишнее, вернуть ошибку
Такого нет. И чистый r2dbc это тоже не поддерживает. Это фишка Spring Data JPA, который может быть обёрткой для r2dbc. И я бы не сказал, что в Repository получается намного меньше кода. + для сложных запросов можно использовать query-dsl, который дружит с хибером.
Для Hibernate Reactive (а точнее для smallrye-mutiny, который в нём используется) есть возможность выполнить преобразования Uni/Multy <-> Mono/Flux. Так что если сейчас используется JPA/Hibernate, особых проблем быть не должно.
при изменении реализации DbClient сломается интеграционный тест. мок не сломается, т.к. его поведение задаётся в тесте
что вы подразумеваете под контрактом?
пример
пример очень простой, но для более сложных случаев разница будет лишь в количестве тестов и моков. поведение мокается в самом тестовом методе, и для разных случаев можно определить разное поведение.
если такая операция вызывается только извне, создаётся обработчик для неё (handler/operation), последовательно вызывающий шаги (service)
можно использовать движок бизнес-процессов, где "создание заявки на кредит" выделено в отдельный процесс, который можно переиспользовать. и вызываться он будет непосредственно движком БП.
если операция должна переиспользоваться в рамках приложения, можно сделать класс типа "сервис", который и будет фасадом. но в случае, если это какие-то крупные шаги, придётся всё-таки нарушить правило "сервис не вызывает сервис".
если данная операция может выполнятся асинхронно, можно реализовать отправку сообщения в рамках одного приложения, использовав либо внешний брокер, либо возможности языка/фреймворка, чтобы положить событие в какую-то внутреннюю очередь. дальнейшая обработка согласно п. 1.
для моков интерфейс не нужен. не скажу за другие ЯП, но в Java всё прекрасно мокается без использования интерфейсов
можно, но это не будет так хорошо масштабироваться по мере роста проекта
враньё. я могу не заполнять поля в запросе. и это будет корректно с т.з. proto. а вот null выставить явно нельзя. только тут про это ни слова.
у меня на одной руке longines, чтобы смотреть дату-время (а ещё они красивые), а на другой браслет xiaomi с будильником и прочими уведомлениями. удобно.
у спецификации asyncApi есть особенность - там описываются параметры и запросов и ответов, а также топики/очереди, куда они кладутся (или откуда берутся). этим она принципиально отличается от openApi.
Ситуация:
сервис ServiceA умеет отправлять сообщения формата FormatA и получать сообщения формата FormatB
сервис ServiceB умеет отправлять сообщения формата FormatB и читать сообщения формата FormatA
вопросы:
где должна лежать спецификация в этом случае, в сервисе ServiceA или в сервисе ServiceB?
где будет лежать спецификация, если схема взаимодействия усложнится и количество сервисов увеличится?
Если бы контракт содержал только описание моделей, то можно было бы держать его в сервисе-отправителе.
Лайфхак - если непосредственно перед генерацией в контракте заменить
asyncapi: 2.6.0
наopenapi: 3.0.2
, а модели предварительно вынести в блокдля генерации моделей можно будет использовать gradle-плагин.
спросите легендарную hr хоум кредита, как мотивировать сотрудника. удивлён, что её не пригласили в качестве эксперта.
Отчасти с вами согласен, в массиве ошибок ошибки пишутся в произвольном формате, который схемой не задаётся. На нашем проекте о нём мы просто договорились. На бэке он генерится
Однако, если в email пришёл null, то это и есть null, т.к. в противном случае пришла бы ошибка.
про schema-first не понял
Можно генерить код из схемы, тогда конфликтов не будет, а вам не придётся писать лишний код. Мы используем для генерации graphql-java-codegen. Он позволяет генерить как DTO, так и интерфейсы API, которые потом можно реализовать, используя ваш любимый фрейсворк.
Убираем обязательность из полей ответа. Клиент сам может решить, что ему запрашивать.
Пишем ошибку доступа в стандартный блок ошибок.
И не нужно заморачиваться с юнионами
PersonItem/PersonError
.PostgREST даст вам возможность не только логику в БД положить, но и выставить наружу API! Вот только стоит ли так делать?
На Android в приложении Сбера работает
Вопрос не понял
Сейчас это не реализовано, но можно где-то в БД держать список полей, доступных роли. При запросе к API Gateway можно сравнить запрашиваемые поля с доступными и, в случае если запрошено что-то лишнее, вернуть ошибку
Такого нет. И чистый r2dbc это тоже не поддерживает. Это фишка Spring Data JPA, который может быть обёрткой для r2dbc. И я бы не сказал, что в Repository получается намного меньше кода. + для сложных запросов можно использовать query-dsl, который дружит с хибером.
Для Hibernate Reactive (а точнее для smallrye-mutiny, который в нём используется) есть возможность выполнить преобразования Uni/Multy <-> Mono/Flux. Так что если сейчас используется JPA/Hibernate, особых проблем быть не должно.