我有一个带有动态创建路由的网关服务。我希望它通过 Swagger UI 公开其端点。由于我的路由不是静态的(它们随着新服务在 Eureka 上注册和注销而来来去去),因此我不能纯粹使用静态 yaml 来完成此操作(如 so)。所以我所做的是:
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: true
path: /swagger-ui.html
config-url: /swagger-ui-config
package by.afinny.apigateway.controller;
import by.afinny.apigateway.model.uiConfig.SwaggerUiConfig;
import by.afinny.apigateway.service.SwaggerUiConfigProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
@RequiredArgsConstructor
public class SwaggerUiConfigController {
private final SwaggerUiConfigProvider configProvider;
@GetMapping("/swagger-ui-config")
public Mono<SwaggerUiConfig> getConfig() {
return configProvider.getSwaggerUiConfig();
}
}
package by.afinny.apigateway.model.uiConfig;
import by.afinny.apigateway.model.documentedApplication.SwaggerApplication;
import by.afinny.apigateway.service.SwaggerUiConfigSerializer;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.Collection;
@NoArgsConstructor
@Getter
public class SwaggerUiConfig {
@JsonProperty("urls")
@JsonSerialize(contentUsing = SwaggerUiConfigSerializer.class)
private Collection<SwaggerApplication> swaggerApplications;
public SwaggerUiConfig(Collection<SwaggerApplication> swaggerApplications) {
this.swaggerApplications = swaggerApplications;
}
public static SwaggerUiConfig from(Collection<SwaggerApplication> swaggerApplications) {
return new SwaggerUiConfig(swaggerApplications);
}
}
package by.afinny.apigateway.service;
import by.afinny.apigateway.model.documentedApplication.SwaggerApplication;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.SneakyThrows;
import java.io.IOException;
import java.text.MessageFormat;
public class SwaggerUiConfigSerializer extends JsonSerializer<SwaggerApplication> {
@Override
@SneakyThrows
public void serialize(SwaggerApplication swaggerApplication, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("url", MessageFormat.format("/{0}{1}", swaggerApplication.getName(), SwaggerApplication.SWAGGER_DOC_PATH));
jsonGenerator.writeStringField("name", swaggerApplication.getName());
jsonGenerator.writeEndObject();
}
}
lb://SERVICE-NAME/v3/api-docs
// I'll omit that code
我不会提供所有代码,因为这并不重要,而且我不想让您不知所措。我想向您展示一般流程
但事情是这样的:我已经获取了这些 JSON 文档来构建我的业务路由(每个端点的路由),它们已经存储在内存中(并更新)。我不想经历所有这些大惊小怪只是为了让 Swagger 做再次获取文档的不必要的额外工作
我可以以某种方式直接提供 Swagger UI 文档,而不是告诉它在哪里可以找到它们吗?
我能找到的最直接的方法是为配置和文档本身编写端点。文档端点可能会返回缓存的
OpenAPI
对象
package com.example.dynamicgateway.controller;
import com.example.dynamicgateway.model.uiConfig.SwaggerUiConfig;
import com.example.dynamicgateway.service.swaggerUiSupport.SwaggerUiSupport;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
@RequiredArgsConstructor
public class SwaggerUiConfigController {
private final SwaggerUiSupport uiSupport;
@GetMapping("/swagger-ui-config")
public Mono<SwaggerUiConfig> getConfig() {
return uiSupport.getSwaggerUiConfig();
}
}
package com.example.dynamicgateway.controller;
import com.example.dynamicgateway.service.swaggerUiSupport.SwaggerUiSupport;
import io.swagger.v3.oas.models.OpenAPI;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
@RequiredArgsConstructor
public class SwaggerDocController {
private final SwaggerUiSupport uiSupport;
@GetMapping("{application-name}/doc")
public Mono<OpenAPI> getSwaggerAppDoc(@PathVariable("application-name") String applicationName) {
// return cached OpenAPI object right away
return uiSupport.getSwaggerAppDoc(applicationName);
}
}
package com.example.dynamicgateway.model.uiConfig;
import com.example.dynamicgateway.model.documentedApplication.SwaggerApplication;
import com.example.dynamicgateway.service.swaggerUiSupport.SwaggerUiConfigSerializer;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.Collection;
@NoArgsConstructor
@Getter
public class SwaggerUiConfig {
@JsonProperty("urls")
@JsonSerialize(contentUsing = SwaggerUiConfigSerializer.class)
private Collection<SwaggerApplication> swaggerApplications;
public SwaggerUiConfig(Collection<SwaggerApplication> swaggerApplications) {
this.swaggerApplications = swaggerApplications;
}
public static SwaggerUiConfig from(Collection<SwaggerApplication> swaggerApplications) {
return new SwaggerUiConfig(swaggerApplications);
}
}
package com.example.dynamicgateway.service.swaggerUiSupport;
import com.example.dynamicgateway.model.documentedApplication.SwaggerApplication;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.SneakyThrows;
import java.text.MessageFormat;
public class SwaggerUiConfigSerializer extends JsonSerializer<SwaggerApplication> {
@Override
@SneakyThrows
public void serialize(SwaggerApplication swaggerApplication, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("url", MessageFormat.format("/{0}/doc", swaggerApplication.getName()));
jsonGenerator.writeStringField("name", swaggerApplication.getName());
jsonGenerator.writeEndObject();
}
}
springdoc:
swagger-ui:
enabled: true
path: /swagger-ui.html
config-url: /swagger-ui-config