Публичные контракты, как обеспечить их согласованность
Нужно что-то предпринять
Нужно что-то предпринять
Как сделать так, чтобы такое больше не повторялось
Экосистема Sungero
Экосистема Sungero
Проблема. В каждом сервисе своя реализация клиента StorageServiceClientProxy
Проблема. В каждом сервисе своя реализация клиента StorageServiceClientProxy
Постановка задачи
Постановка задачи
Инструменты
REST vs RPC
Где расположить контракты? Как осуществить доступ сервисов к контрактам?
Где расположить контракты? Как осуществить доступ сервисов к контрактам?
В какой момент выполнять генерацию?
В какой момент выполнять генерацию?
Где расположить код клиента?
Где расположить код клиента?
Где расположили код клиента
Детали реализации
DescriptionController.cs
FileController.cs
Процессор
Конфигурация Nswag.json
Как добавили поддержку JWT
Как добавили поддержку JWT
Как добавили поддержку JWT
Как добавили поддержку JWT
Вывод
Вывод
Версионирование
Версионирование
Версионирование
Версионирование
Версионирование
Когда вводить новую версию
Тестирование контрактов
Consumer driven contracts
Спасибо за внимание!
REST + gRPC
Настройка csproj
Как CDC можно встроить в CI
Процессор
WSDL
Версионирование

Публичные контракты, как обеспечить их согласованность

1. Публичные контракты, как обеспечить их согласованность

Романюк Антон
1

2.

Сервис
потребитель
Сервис
потребитель
Сервис
потребитель
Сервис
поставщик
2

3.

Сервис
потребитель
Сервис
потребитель
Сервис
потребитель
Сервис
поставщик
Изменение контрактов
3

4.

Сервис
потребитель
Сервис
потребитель
Сервис
потребитель
Сервис
поставщик
Изменение контрактов
4

5. Нужно что-то предпринять

[Красноречие] Команда сервиса поставщика сама всё поправит
[Удача] Актуализировать код своего сервиса
[Интеллект] Как сделать так, чтобы такое больше не повторялось?
Сарказм
5

6. Нужно что-то предпринять

[Красноречие] Команда сервиса поставщика сама всё поправит
[Удача] Актуализировать код своего сервиса
[Интеллект] Как сделать так, чтобы такое больше не повторялось?
Сарказм
6

7. Как сделать так, чтобы такое больше не повторялось

Проектирование
• Унифицировать описание контрактов
Реализация
• Автоматизировать генерацию кода сервера и клиента
• Версионировать API
Тестирование
• Тестировать контракты
• Учитывать потребности клиентов
7

8. Экосистема Sungero

8

9. Экосистема Sungero

9

10.

Экосистема Sungero
10

11. Проблема. В каждом сервисе своя реализация клиента StorageServiceClientProxy

11

12. Проблема. В каждом сервисе своя реализация клиента StorageServiceClientProxy

12

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

Нужно генерировать код клиента
Генерация должна настраиваться, например, для JWT
Сервисы взаимодействуют по http
Браузер клиент сервиса
Серверная часть – контроллеры уже написаны
13

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

Нужно генерировать код клиента
Генерация должна настраиваться, например, для JWT
Сервисы взаимодействуют по http
Браузер клиент сервиса
Серверная часть – контроллеры уже написаны
14

15.

Вход: описание контрактов
Вопросы:
Какой
инструмент
выбрать
Как
получить
контракты
Где
расположить
контракты
Где
расположить
код клиента
Выход: код для сервера и клиента
В какой
момент
выполнять
генерацию
15

16. Инструменты

RPC
REST
16

17. REST vs RPC

REST Representational State Transfer
Методы и процедуры
Ресурсы, HTTP глаголы и URL
http://Restaurant:8080/Orders/GetOrder
?OrderNumber=1
http://Restaurant:8080/Orders/UpdateOrder
http://Restaurant:8080/Orders
GET
http://Restaurant:8080/Orders/PlaceOrder
POST
RPC – Remote procedure call
http://Restaurant:8080/Orders/1
PUT
Изменение Получение
Создание
REST vs RPC
http://Restaurant:8080/Orders/1
17

18.

Свойства
OpenAPI
Тип
WSDL
Thrift
REST
gRPC
RPC
Платформа
Не зависит
Язык
Не зависит
Последователь code first
ность
spec first
разработки*
code first
spec first
spec first
spec first
code first
Транспортный
протокол
HTTP/1.1
любой (REST
требует HTTP)
собственный
HTTP/2
Вид
спецификация
Комментарий
Низкий порог
вхождения, много
документации
фреймворк
Избыточность
XML, тянет за
собой SOAP и
т.п.
Высокий порог
вхождения,
мало
документации
Средний порог
вхождения, лучше
документация
18

19.

Свойства
OpenAPI
WSDL
Thrift
REST
Тип
Платформа
gRPC
RPC
Не зависит
Не зависит
Язык
Последователь code first
ность
spec first
разработки*
code first
spec first
spec first
spec first
code first
Транспортный
протокол
HTTP/1.1
любой (REST
требует HTTP)
собственный
HTTP/2
Вид
спецификация
Комментарий
Низкий порог
вхождения, много
документации
фреймворк
Избыточность
XML, тянет за
собой SOAP и
т.п.
Высокий порог
вхождения,
мало
документации
Средний порог
вхождения, лучше
документация
19

20.

Свойства
OpenAPI
Тип
WSDL
Thrift
REST
gRPC
RPC
Платформа
Не зависит
Язык
Не зависит
Последователь code first
ность
spec first
разработки*
code first
spec first
spec first
spec first
code first
Транспортный
протокол
HTTP/1.1
любой (REST
требует HTTP)
собственный
HTTP/2
Вид
спецификация
Комментарий
Низкий порог
вхождения,
много
документации
фреймворк
Избыточность
XML, тянет за
собой SOAP и
т.п.
Высокий порог
вхождения,
мало
документации
Средний порог
вхождения, лучше
документация
20

21.

Свойства
OpenAPI
Тип
WSDL
Thrift
REST
gRPC
RPC
Платформа
Не зависит
Язык
Не зависит
Последователь code first
ность
spec first
разработки*
code first
spec first
spec first
Транспортный
протокол
HTTP/1.1
любой (REST собственный
требует HTTP)
Вид
спецификация
Комментарий
Низкий порог
вхождения, много
документации
spec first
code first
HTTP/2
фреймворк
Избыточность
XML, тянет за
собой SOAP и
т.п.
Высокий порог
вхождения,
мало
документации
Средний порог
вхождения, лучше
документация
21

22.

Свойства
OpenAPI
Тип
WSDL
Thrift
REST
gRPC
RPC
Платформа
Не зависит
Язык
Не зависит
Последователь code first
ность
spec first
разработки*
code first
spec first
spec first
spec first
code first
Транспортный
протокол
HTTP/1.1
любой (REST
требует HTTP)
собственный
HTTP/2
Вид
спецификация
Комментарий
Низкий порог
вхождения, много
документации
фреймворк
Избыточность
XML, тянет за
собой SOAP и
т.п.
Высокий порог Средний порог
вхождения, лучше
вхождения,
документация
мало
документации
22

23.

Свойства
OpenAPI
Тип
WSDL
Thrift
REST
gRPC
RPC
Платформа
Не зависит
Язык
Не зависит
Последователь code first
ность
spec first
разработки*
code first
spec first
spec first
spec first
code first
Транспортный
протокол
HTTP/1.1
любой (REST
требует HTTP)
собственный
HTTP/2
Вид
спецификация
Комментарий
Низкий порог
вхождения, много
документации
фреймворк
Избыточность
XML, тянет за
собой SOAP и
т.п.
Высокий порог
вхождения,
мало
документации
Средний порог
вхождения,
лучше
документация
23

24.

Свойства
OpenAPI
WSDL
Thrift
REST
Тип
gRPC
RPC
Платформа
Не зависит
Язык
Не зависит
Последователь code first
ность
spec first
разработки*
code first
spec first
spec first
spec first
code first
Транспортный
протокол
HTTP/1.1
любой (REST
требует HTTP)
собственный
HTTP/2
Вид
спецификация
Комментарий
Низкий порог
вхождения, много
документации
фреймворк
Избыточность
XML, тянет за
собой SOAP и
т.п.
Высокий порог
вхождения,
мало
документации
Средний порог
вхождения, лучше
документация
24

25.

Требует net Core 3.0 и net
Standard 2.1
Не требует
дополнительных
обновлений
Требует HTTP/2
Нет поддержки в браузере
из коробки
Обилие инструментов
поддерживающих работу
со спецификацией
25

26.

Требует net Core 3.0 и net
Standard 2.1
Не требует
дополнительных
обновлений
Требует HTTP/2
Нет поддержки в браузере
из коробки
Обилие инструментов
поддерживающих работу
со спецификацией
26

27.

swashbuckle
NSwag
OpenAPITools
Поддерживаемые
версии
спецификации
Могут генерировать спецификацию в формате
OpenApi v2, v3
Поддержка
code first
Есть
Есть
Нет
Поддерживаемые
языки сервера
Нет
C#
Много
Поддерживаемые
шаблоны клиентов
Нет
C#, TypeScript,
AngularJS,
Angular (v2+),
window.fetch API
Много
Есть
Есть
Настройки генерации Нет
27

28.

swashbuckle
NSwag
OpenAPITools
Поддерживаемые
версии
спецификации
Могут генерировать спецификацию в формате
OpenApi v2, v3
Поддержка
code first
Есть
Есть
Нет
Поддерживаемые
языки сервера
Нет
C#
Много
Поддерживаемые
шаблоны клиентов
Нет
C#, TypeScript,
AngularJS,
Angular (v2+),
window.fetch API
Много
Есть
Есть
Настройки генерации Нет
28

29.

swashbuckle
NSwag
OpenAPITools
Поддерживаемые
версии
спецификации
Могут генерировать спецификацию в формате OpenApi
v2, v3
Поддержка
code first
Есть
Есть
Нет
Поддерживаемые
языки сервера
Нет
C#
Много
Поддерживаемые
шаблоны клиентов
Нет
C#, TypeScript,
AngularJS,
Angular (v2+),
window.fetch API
Много
Есть
Есть
Настройки генерации Нет
29

30.

Поддерживаемые
версии
спецификации
Поддержка
code first
Поддерживаемые
языки сервера
Поддерживаемые
шаблоны клиентов
swashbuckle
NSwag
OpenAPITools
Могут генерировать спецификацию в формате OpenApi
v2, v3
Есть
Есть
Нет
Нет
C#
Много
Нет
C#, TypeScript,
AngularJS,
Angular (v2+),
window.fetch API
Есть
Много
Настройки генерации Нет
Есть
30

31.

swashbuckle
NSwag
OpenAPITools
Поддерживаемые
версии
спецификации
Могут генерировать спецификацию в формате OpenApi
v2, v3
Поддержка
code first
Поддерживаемые
языки сервера
Есть
Есть
Нет
Нет
C#
Много
Поддерживаемые
шаблоны клиентов
Нет
C#, TypeScript,
AngularJS,
Angular (v2+),
window.fetch API
Много
Есть
Есть
Настройки генерации Нет
31

32.

swashbuckle
NSwag
OpenAPITools
Поддерживаемые
версии
спецификации
Могут генерировать спецификацию в формате OpenApi
v2, v3
Поддержка
code first
Поддерживаемые
языки сервера
Есть
Есть
Нет
Нет
C#
Много
Поддерживаемые
шаблоны клиентов
Нет
C#, TypeScript,
AngularJS,
Angular (v2+),
window.fetch API
Много
Есть
Есть
Настройки генерации Нет
32

33. Где расположить контракты? Как осуществить доступ сервисов к контрактам?

Папка проекта
Общая папка
Через API сервиса (swagger.ui)
Отдельный репозиторий для спецификаций
Менеджер пакетов (swaggerhub)
33

34. Где расположить контракты? Как осуществить доступ сервисов к контрактам?

Папка проекта
Общая папка
Через API сервиса (swagger.ui)
Отдельный репозиторий для спецификаций
Менеджер пакетов (swaggerhub)
34

35. В какой момент выполнять генерацию?

Сервис потребитель генерирует сам по необходимости
После сборки проекта web сервиса поставщика
35

36. В какой момент выполнять генерацию?

Сервис потребитель генерирует сам по необходимости
После сборки проекта web сервиса поставщика
36

37. Где расположить код клиента?

37

38. Где расположить код клиента?

38

39. Где расположили код клиента

39

40. Детали реализации

Атрибуты контроллеров
Процессор для генерации спецификации для файловых
операций
Конфигурация Nswag для генерации спецификации и кода
Как добавили поддержку для JWT
40

41. DescriptionController.cs

[Route("[controller]")]
[ApiController]
public class DescriptionController : ControllerBase {
[OpenApiOperation("GetDescription")]
[ProducesResponseType(typeof(ConversionDescription), 200)]
[ProducesResponseType(401)]
[ProducesResponseType(403)]
[HttpGet("{pluginName}/{binaryDataId}")]
public ActionResult<ConversionDescription> GetDescription(
string pluginName, Guid binaryDataId) { // код... }
41

42. FileController.cs

[Route("[controller]")]
[ApiController]
public class FileController : ControllerBase {
[OpenApiOperation("SaveFile")]
[ProducesResponseType(401)]
[ProducesResponseType(403)]
[HttpPost("{pluginName}/{binaryDataId}/{fileName}")]
[FileUploadOperation]
public async Task SaveFile() { // код... }
42

43. Процессор

FileUploadOperationAttribute :
OpenApiOperationProcessorAttribute
FileUploadOperationProcessor :
IOperationProcessor
43

44. Конфигурация Nswag.json

"runtime": "NetCore22",
"documentGenerator": {
"webApiToOpenApi": {
"defaultUrlTemplate": "api/{controller}/{id?}",
"infoTitle": "PreviewStorage", "infoVersion": "1.0.0",
"documentName": "v1","allowNullableBodyParameters": true,
"output": "../../api-docs/PreviewStorage_swagger.json",
"outputType": "OpenApi3",
"assemblyPaths": [
"../../bin/$(Configuration)/PreviewStorage/netcoreapp2.2/PreviewStorage.dll“ ], } },
"codeGenerators": { "openApiToCSharpClient": { "input": "../../api-docs/PreviewStorage_swagger.json",
"namespace": "PreviewStorage.WebApiProxy",
"generateClientInterfaces": true,
"useHttpRequestMessageCreationMethod": true,
“httpClientType": "System.Net.Http.HttpClient",
"additionalNamespaceUsages": [ "PreviewService.Common.Model“ ],
"output": "../PreviewStorage.WebApiProxy/PreviewStorageProxy.g.cs",
"className": "{controller}PreviewStorageProxy",
"operationGenerationMode": "SingleClientFromOperationId“ } } }
44

45. Как добавили поддержку JWT

45

46. Как добавили поддержку JWT

46

47. Как добавили поддержку JWT

47

48. Как добавили поддержку JWT

48

49. Вывод

Спецификация многословна
Генерация прикручивается быстро за счет хорошей документации к
спецификации и инструментам её реализующим
Пришлось докрутить процессор для генерации спецификации
Много атрибутов на контроллерах – отвлекает
49

50. Вывод

Спецификация кажется более человекочитаемой по сравнению с OpenAPI
Использовать пока не имеет смысла без обновления фреймворка и всех зависимых
проектов
Нет поддержки браузером из коробки
Выше уровень абстракции, не нужно явно работать с URL, HTTP и т.п.
Подходит для общения микросервисов по HTTP/2
50

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

После изменений в сервисах поставщиках вся
система должна оставаться в согласованном,
рабочем состоянии
Нужно избежать breaking changes в API, чтобы
не поломать клиентов
51

52.

Варианты решения
Сервис
потребитель
Сервис
потребитель
Команда сервиса
поставщика сама
исправляет сервисы
потребители.
Без версионирования
Сервис
потребитель
Сервис
поставщик
Изменение
контрактов
52

53.

Варианты решения
Сервис
потребитель
Сервис
потребитель
Go
Python
Плохо работает:
• Разные репозитории
• Нет компетенций
Сервис
потребитель
JS
Сервис
поставщик
C#
Изменение
контрактов
53

54.

Варианты решения
Сервис
потребитель
Сервис
потребитель
Команда сервиса
поставщика оставляет
предыдущую версию
контрактов
Сервис
потребитель
Сервис
поставщик
V1, V2
Изменение
контрактов
54

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

gRPC
Атрибут
версии
На уровне protobuf есть атрибут
package [packageName].[Version]
OpenAPI
На уровне спецификации есть атрибуты
basePath (для URL) и Version
Атрибут
Есть, но не учитывается
Deprecated
генератором кода под C#
для методов
Есть, помечается как Obsolete
В Nswag не поддерживается при code
first, нужно писать свой процессор
Атрибут
Deprecated
для
параметров
Есть, помечается как Obsolete
В Nswag не поддерживается при code
first, нужно писать свой процессор
Есть, помечается как Obsolete
55

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

gRPC
Атрибут
версии
На уровне protobuf есть
атрибут package
[packageName].[Version]
OpenAPI
На уровне спецификации есть
атрибуты basePath (для URL) и
Version
Атрибут
Есть, но не учитывается
Deprecated
генератором кода под C#
для методов
Есть, помечается как Obsolete
В Nswag не поддерживается при code
first, нужно писать свой процессор
Атрибут
Deprecated
для
параметров
Есть, помечается как Obsolete
В Nswag не поддерживается при code
first, нужно писать свой процессор
Есть, помечается как Obsolete
56

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

gRPC
Атрибут
версии
OpenAPI
На уровне protobuf есть атрибут На уровне спецификации есть атрибуты
package [packageName].[Version] basePath (для URL) и Version
Атрибут
Есть, но не учитывается
Deprecated
генератором кода под C#
для методов
Есть, помечается как Obsolete
В Nswag не поддерживается при
code first, нужно писать свой
процессор
Атрибут
Deprecated
для
параметров
Есть, помечается как Obsolete
В Nswag не поддерживается при code first,
нужно писать свой процессор
Есть, помечается как Obsolete
57

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

gRPC
Атрибут
версии
На уровне protobuf есть атрибут
package [packageName].[Version]
OpenAPI
На уровне спецификации есть атрибуты
basePath (для URL) и Version
Атрибут
Есть, но не учитывается
Deprecated
генератором кода под C#
для методов
Есть, помечается как Obsolete
В Nswag не поддерживается при code
first, нужно писать свой процессор
Атрибут
Deprecated
для
параметров
Есть, помечается как Obsolete
В Nswag не поддерживается при
code first, нужно писать свой
процессор
Есть, помечается как
Obsolete
58

59. Когда вводить новую версию

Для OpenAPI есть инструмент Azure
opeanapi-diff проверки совместимости
между 2 спецификациями
Для gRPC автоматического инструмента не
обнаружил, есть только политики
версионировния
59

60. Тестирование контрактов

Consumer driven contracts (CDC)
Pact
Как CDC можно встроить в CI
60

61. Consumer driven contracts

61

62.

62

63.

Pact + Pact broker - самостоятельно
Pact Flow SaaS – приобрести
63

64. Спасибо за внимание!

Разработчик Directum
в г. Уфа Романюк Антон
[email protected]
64

65. REST + gRPC

65

66. Настройка csproj

Создали WebApi проект для клиента
Написали конфиг для Nswag CLI – Nswag.json
Написали PostBuild Target внутри csproj проекта сервиса поставщика
<Target Name="GenerateWebApiProxyClient“ AfterTargets="PostBuildEvent">
<Exec Command="$(NSwagExe_Core22) run nswag.json
/variables:Configuration=$(Configuration)" />
</Target>
66

67. Как CDC можно встроить в CI

67

68. Процессор

public class FileUploadOperationAttribute : OpenApiOperationProcessorAttribute {
public FileUploadOperationAttribute() : base(typeof(FileUploadOperationProcessor)) { } }
public class FileUploadOperationProcessor : IOperationProcessor {
public bool Process(OperationProcessorContext context) {
var parameters = context.OperationDescription.Operation.Parameters;
parameters.Add(new OpenApiParameter() {
Name = "stream", Kind = OpenApiParameterKind.Body,
Schema = new JsonSchema { Type = JsonObjectType.String, Format = "binary" },
IsRequired = true, Description = "Файл.",
});
68
return true; } }

69. WSDL

• Language, platform, and transport independent (REST requires use of
HTTP)
• Works well in distributed enterprise environments (REST assumes
direct point-to-point communication)
• Standardized
• Provides significant pre-build extensibility in the form of the WS*
standards
• Built-in error handling
• Automation when used with certain language products
69

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

Использовать номер версии в URL
сервиса http://service:8080/api/v1/action
• Как часто меняются контракты
• Как выглядит идентификатор версии в URL
• Как долго поддерживать прошлые версии
70

71.

71

72.

• https://servicesblog.redhat.com/2019/01/31/comparing-openapiwith-grpc/
• https://docs.microsoft.com/enus/aspnet/core/grpc/comparison?view=aspnetcore-3.1
• https://blog.maddevs.io/introduction-to-grpc-6de0d9c0fe61
• https://github.com/Azure/openapi-diff
• https://www.davidkaya.com/with-openapi-against-breaking-changes/
• https://github.com/grpc/grpc-web/issues/517 не подойдет для
передачи больших файлов
• https://developers.google.com/protocolbuffers/docs/techniques?hl=en#large-data сообщения не больше 1
мб
• https://app.swaggerhub.com/help/integrations/api-auto-mocking
72

73.

swashbuckle
NSwag
OpenAPITools
Свой инструмент
Поддерживаемые Могут генерировать спецификацию в формате
версии
OpenApi v2, v3
спецификации
Ad hoc решение,
зато умеет
генерировать js для
SignalR
Поддержка
code first
Есть
Есть
Нет
Да\Нет
Поддерживаемые Нет
языки точек
доступа
C#
Много
Нет
Поддерживаемые Нет
шаблоны
клиентов
C#, TypeScript,
AngularJS,
Angular (v2+),
window.fetch API
Много
TypeScript
Настройки
Есть
Есть
Нет
Нет
73

74.

• PACT и OpenAPI (REST)
• PACT и gRPC
• PACT и Message Queues
74
English     Русский Правила