Публикация документации API во всей системе микросервисов может быть затруднена. Службы небольшие и разделены, они могут находиться за шлюзом API, который изменяет их путь, и предоставление документации должно быть безопасным.
У нас есть много микросервисов в Mettle , и они должны быть задокументированы и доступны для использования API. Иногда API, необходимые разработчикам интерфейсов, уже существуют, но они об этом не знают. Наличие единого места для всей документации API снижает вероятность недопонимания и трений между командами.
У меня было несколько требований к нашей документации по API:
- Все это должно быть в одном месте, в одном пользовательском интерфейсе – каждая служба должна просто обслуживать Чванство JSON или YAML и не имеют чванливого пользовательского интерфейса
- Пользовательский интерфейс документации должен находиться за единым входом, а конечные точки документации должны быть безопасными
- Пользовательский интерфейс и конечные точки для запроса документов Swagger должны находиться на одном хосте, поэтому нет необходимости настраивать CORS в каждой службе
- Даже при использовании шлюза API, который изменяет путь, путь запроса в документах должен быть правильным, чтобы вы могли опробовать запрос
Для этого я использовал Spring Cloud Gateway для динамической генерации маршрутов на основе конфигурации. У каждой службы есть URL-адрес, с которого отправляются документы API, и префикс шлюза – это то, что шлюз API добавляет в путь для всех запросов API. Например, в приложении.ямл
:
api-docs.endpoints: service-name: gateway-prefix: /api service-url: http://service.namespace service-path: /resource/api-docs
Эти свойства предоставляются во всем приложении в виде @ConfigurationProperties
класса, Конфигурация конечных точек ApiDoc
.
Настройка пользовательского интерфейса Swagger для обслуживания нескольких документов API
Список настроенных служб используется для генерации ответа на /swagger-config.json
, который является конечной точкой, которую пользовательский интерфейс запрашивает для получения своей конфигурации. В этом мы предоставляем список URL-адресов, которые будут перенаправлять запросы на документацию по каждому из микросервисов.
@RestController @Hidden public class SwaggerConfigController { @Autowired private ApiDocEndpointsConfiguration apiDocEndpoints; @GetMapping("/swagger-config.json") public SwaggerUrlsConfig swaggerConfig() { Listurls = apiDocEndpoints.getEndpoints() .entrySet().stream().map(routeEntry -> { String name = routeEntry.getKey(); return SwaggerUrlsConfig.SwaggerUrl.builder() .url(routeEntry.getValue().getGatewayPrefix() + routeEntry.getValue().getServicePath()) .name(name).build(); }).collect(Collectors.toList()); return new SwaggerUrlsConfig(urls); } @Data @Builder @NoArgsConstructor @AllArgsConstructor public static class SwaggerUrlsConfig { private List urls; @Data @Builder @NoArgsConstructor @AllArgsConstructor public static class SwaggerUrl { private String url; private String name; } } }
Мы используем Springfox для обслуживания пользовательского интерфейса Swagger, для которого просто требуется зависимость:
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.2.33'
и некоторые настройки:
springdoc: swagger-ui: path: / configUrl: /swagger-config.json
Это означало, что пользовательский интерфейс получит вашу пользовательскую конфигурацию, обслуживаемую контроллером конфигурации Swagger
, и отобразит список микросервисов с документацией API.
Настройка каждого микросервиса
Каждая служба обслуживает свой собственный JSON или YAML Swagger, и это не проходит проверку подлинности, чтобы шлюз документации мог получить их для пользовательского интерфейса. Разрешены только запросы из кластера, поэтому он недоступен через шлюз API.
Настройка шлюза документации для запросов прокси-сервера
Шлюз документации прокси-серверы запрашивает документы Swagger для служб в кластере, а затем отображает их в пользовательском интерфейсе, который он также предоставляет. Spring Cloud Gateway позволяет настраивать маршруты в коде, а не только в свойствах. Это делается путем предоставления Указателя маршрута
как @Боб
(это должно быть помещено в класс с аннотацией @Configuration
для загрузки Spring, чтобы забрать его):
@Autowired private ApiDocEndpointsConfiguration apiDocEndpoints; @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { RouteLocatorBuilder.Builder routes = builder.routes(); apiDocEndpoints.getEndpoints().forEach((key, endpoint) -> { routes.route(this.routeForJsonResponses(endpoint)); }); return routes.build(); } private FunctionrouteForJsonResponses( ApiDocEndpointsConfiguration.Endpoint endpoint) { return r -> r.path(new PathBuilder(endpoint.getGatewayPrefix(), endpoint.getServicePath()).getPath()) .filters(f -> f.setPath(endpoint.getServicePath())) .uri(endpoint.getServiceUrl()); }
Приведенный выше код показывает построение маршрутов для Spring Cloud Gateway. Для каждой службы с документацией API он настраивает маршрут, который соответствует пути, указанному в /swagger-config.json
ответе, устанавливает новый путь в качестве пути к документам API в службе и изменяет URL-адрес, чтобы он был внутренним URL-адресом Kubernetes службы.
Убедившись, что путь правильный
Если вы используете шлюз API, он обычно изменяет путь запроса. Чтобы убедиться, что пути в документации API верны, нам нужно изменить ответ. Spring Cloud Gateway позволяет нам делать это с помощью фильтра модификации ответов.
private FunctionrouteForJsonResponses( ApiDocEndpointsConfiguration.Endpoint endpoint) { return r -> r.path(new PathBuilder(endpoint.getGatewayPrefix(), endpoint.getServicePath()).getPath()) .filters(f -> f.setPath(endpoint.getServicePath()) # Adding response modification filter .modifyResponseBody(Map.class, Map.class, rewriteServersWithGatewayUrl(endpoint, namespace))) .uri(endpoint.getServiceUrl()); } private RewriteFunction
В приведенном выше примере я добавил фильтр модификации ответа, который десериализует JSON в Карту
. Это позволяет мне добавить URL-адрес шлюза API в качестве открытого сервера API в ответ с настроенным префиксом (если шлюз API вообще изменяет путь).
Защита документов
Наконец, поместите свой пользовательский интерфейс Swagger за провайдером единого входа (например, следуя способу Стива Уэйда сделать это в Kubernetes ) и убедитесь, что к вашему JSON Swagger нельзя получить доступ через ваш шлюз API (потому что он не прошел проверку подлинности на уровне микросервиса, чтобы разрешить Spring Cloud Gateway отправлять к нему прокси-запросы).
Вывод
Я подумал, что это отличный способ использовать шаблон шлюза для объединения документации по микросервисам. Как всегда, есть вещи, которые я хотел бы улучшить, например, сделать конечные точки документации автоматически обнаруживаемыми, а не статически по конфигурации. Кроме того, может быть предпочтительнее объединить документацию в один большой файл, а затем сгруппировать запросы по тегам, а не "сливать", какие службы обслуживают какие ресурсы потребителям.
Оригинал: "https://dev.to/philhardwick/distributed-api-documentation-how-to-aggregate-swagger-4fnj"