Рубрики
Без рубрики

Документация по распределенному API – Как агрегировать Swagger

Публикация документации API во всей системе микросервисов может быть затруднена. Услуги ar… С тегами spring, swagger, микросервисы, java.

Публикация документации 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() {
        List urls = 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 Function
 routeForJsonResponses(
    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 Function
 routeForJsonResponses(
    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 rewriteServersWithGatewayUrl(
    ApiDocEndpointsConfiguration.Endpoint endpoint) {
    return (serverWebExchange, openAPI) -> {
        Server server = new Server();
        server.setUrl("https://api.domain.com" + endpoint.getGatewayPrefix());
        openAPI.put("servers", Collections.singletonList(server));
        return Mono.just(openAPI);
    };
}

В приведенном выше примере я добавил фильтр модификации ответа, который десериализует 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"