Swagger UI - Load custom file.yaml/json instead default configuration - spring-boot

I'm developing an SpringBoot REST project which runs perfectly. I'm trying to implement the OpenApi-ui in the project. It's working fine by default but I'd like to use my own yaml/json information file instead the default info.
I have been following the F.A.Q SpringDoc documentation , but nothing is working for me. It's throwing FAILED TO LOAD API DEFINITION : Fetch error undefined /open-api.yaml in the UI. Am I missing something in my configuration?
Thanks in advance.
Implementation
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.5.9'
App config (route yaml = src/main/resources)
springdoc:api-docs:enabled: false
swagger-ui:url: /open-api.yaml
Configuration
#Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.components(new Components().addSecuritySchemes("basicScheme",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")))
.info(new Info().title("MyApp").version("1.0")
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}
#Bean
public SpringDocConfiguration springDocConfiguration(){
return new SpringDocConfiguration();
}
#Bean
public SpringDocConfigProperties springDocConfigProperties() {
return new SpringDocConfigProperties();
}
Yaml file
openapi: 3.0.3
info:
title: MyApp
description: MyApp Description
version: 1.0.0
servers:
- url: http://localhost:8080
description: Local server
{...more}
Access URL to OpenApi UI
http://localhost:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config
OpenApi UI Image

Just if someone is looking for something similar, we finally created a new class, extending SwaggerIndexPageTransformer and implementing by SwaggerIndexTransformer , which led us to use #override method to change the url.
You can follow > https://github.com/springdoc/springdoc-openapi/issues/763

Related

Not working added global header parameters using Swagger 3 UI

I have migrated existing project Swagger to Swagger3 using dependency springdoc-openapi-ui 1.6.8 version .
Getting issue while added the global header parameter in Swagger config file, it was not showing at Swagger dashboard
Please advised me if any issue in mentioned code.
Code:
**
#Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.components(new Components()
.addSecuritySchemes("basicScheme",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic"))
.addParameters("myHeader1",
new Parameter().in("header").schema(new StringSchema()).name("myHeader1"))
.addHeaders("myHeader2",
new Header().description("myHeader2 header").schema(new StringSchema())))
.info(new Info().title("eWallet API Sandbox").description("eWallet API Sandbox").version("v1.0")
.contact(new Contact().name("WOW Finstack").url("https://wowdigital.ai/")
.email("info#wowdigital.ai"))
.termsOfService("WOW Finstack").license(new License().name("License").url("#")));
//
};
**
Dependency :
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.8</version>
</dependency>
I recently upgraded to springdoc-openapi-ui and struggled a bit to make global headers work on Spring boot 2.6.3.
I managed to make global header work if it's defined as a Parameter (using new Parameter()...) but I did not make it work when defined as a Header (using new Header()...)
I guess that you already defined a GroupedOpenApi Spring Bean. So what you have to do is add a OpenApiCustomiser to this GroupedOpenApi, see addOpenApiCustomiser(globalHeaderCustomizer()) below:
#Bean
public GroupedOpenApi publicGroup() {
return GroupedOpenApi.builder()
.packagesToScan("com.my.package")
.pathsToMatch("/**")
.group("public")
.addOpenApiCustomiser(globalHeaderCustomizer()) // --> you need this!
.build();
}
where globalHeaderCustomizer() is:
private OpenApiCustomiser globalHeaderCustomizer() {
return openApi -> openApi.getPaths().values().stream().flatMap(pathItem -> pathItem.readOperations().stream())
.forEach(operation -> operation.addParametersItem(
new HeaderParameter().$ref("#/components/parameters/myHeader1")));
}
I think that should fix your issue.

Spring doc oauth2RedirectUrl with wrong server

I'm writing my first question, please be patient if anything is missing. Any Feedback is welcome.
We have an issue with the generated oauth2RedirectUrl after migrating from a Windows 2012 R2 to a Windows 2016. The server is no longer containing the alias name but the technical server name.
We are using Spring Boot 2.6.0 including spring-boot-starter-oauth2-resource-server and springdoc-openapi-ui 1.5.12.
Spring Boot is set up as a resource server with JWT authorization with Azure OAuth2.
We deploy a FAT Jar on windows machines and recently changed to a new server.
Each machine is has a DNS entry with a technical name and a human readable alias.
Lets say
human-readable-name1 for the old machine
human-readable-name2 for the new machine
We deployed the exact same software on both machines. We access the sawagger ui
with
https://human-readable-name1.domain:port/swagger-ui.html
and
https://human-readable-name2.domain:port/swagger-ui.html
The response from both machines include the generated api-docs which are looking fine.
Containing on both machines like
"servers": [
{
"url": "https://human-readable-name.domain:port",
"description": "Generated server url"
}
]
But the swagger-config change
OLD
{
"configUrl": "/v3/api-docs/swagger-config",
"oauth2RedirectUrl": "https://human-readable-name1:port/swagger-ui/oauth2-redirect.html",
"url": "/v3/api-docs",
"validatorUrl": ""
}
NEW
{
"configUrl": "/v3/api-docs/swagger-config",
"oauth2RedirectUrl": "https://technicalname:port/swagger-ui/oauth2-redirect.html",
"url": "/v3/api-docs",
"validatorUrl": ""
}
This breaks the log in as the token is no longer reaching the swagger ui client.
Any suggestions where I even can start looking for the reason?
Swagger config:
#Configuration
class OpenApiConfig {
#Value("${springdoc.oAuthFlow.authorizationUrl}")
private String authorizationUrl;
#Value("${springdoc.oAuthFlow.tokenUrl}")
private String tokenUrl;
#Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.components(new Components()
.addSecuritySchemes("security_auth",
new SecurityScheme()
.type(SecurityScheme.Type.OAUTH2)
.flows(new OAuthFlows()
.authorizationCode(new OAuthFlow()
.authorizationUrl(authorizationUrl)
.tokenUrl(tokenUrl)
.scopes(new Scopes()
.addString("xxx", "xxx")
)
)
)
)
)
.addSecurityItem(new SecurityRequirement().addList("security_auth"))
;
}
}
Spring Boot yaml
spring.security.oauth2.resourceserver.jwt:
jwk-set-uri: https://login.microsoftonline.com/common/discovery/v2.0/keys
issuer-uri: https://login.microsoftonline.com/xxx/v2.0
springdoc:
swagger-ui:
oauth:
clientId: 'xxx'
use-pkce-with-authorization-code-grant: true
oAuthFlow:
authorizationUrl: https://login.microsoftonline.com/xxx/oauth2/v2.0/authorize
tokenUrl: https://login.microsoftonline.com/xxx/oauth2/v2.0/token

Spring boot actuator breaks #AutoConfigureMockRestServiceServer

I have a class which builds multiple RestTemplates using RestTemplateBuilder:
private RestTemplate build(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.rootUri("http://localhost:8080/rest")
.build();
}
For my test setup I use #AutoConfigureMockRestServiceServer and mock responses using MockServerRestTemplateCustomizer:
mockServerRestTemplateCustomizer.getServer()
.expect(ExpectedCount.times(2),
requestToUriTemplate("/some/path/{withParameters}", "withParameters"))
.andRespond(withSuccess());
My test passes when I uncomment the spring-boot-actuator dependency in my pom and fails in the other scenario with the following message.
Expected: /some/path/parameter
Actual: http://localhost:8080/rest/pos/some/path/withParameters
I noticed by debugging through MockServerRestTemplateCustomizer that spring-boot-actuator applies a "DelegateHttpClientInterceptor" for supporting their built in metrics for rest templates. However this creates a problem with the following code which I found in RootUriRequestExpectationManager:
public static RequestExpectationManager forRestTemplate(RestTemplate restTemplate,
RequestExpectationManager expectationManager) {
Assert.notNull(restTemplate, "RestTemplate must not be null");
UriTemplateHandler templateHandler = restTemplate.getUriTemplateHandler();
if (templateHandler instanceof RootUriTemplateHandler) {
return new RootUriRequestExpectationManager(((RootUriTemplateHandler) templateHandler).getRootUri(),
expectationManager);
}
return expectationManager;
}
Because as mentioned above spring-boot-actuator registers a "DelegateHttpClientInterceptor" which leads to the above code not recognizing the RootUriTemplateHandler and therefore not matching the request using requestToUriTemplate.
What am I missing here to get this working?
As Andy Wilkinson pointed out, this seems to be a bug in Spring boot. I created an issue with a sample project.

Tesseract in Spring Boot Application gives nonsense results for Japanese

I'm writing a Spring Boot Application that uses Bytedeco's Java Wrapper for Tesseract OCR to parse Japanese text. I've managed to get Tesseract working fine when running outside of Spring Boot, but when I use it from within the Spring Boot application it gives me nonsense results.
For example, given the following image:
If I run the following function, the result is reasonable:
fun main() {
val api = tesseract.TessBaseAPI()
api.Init("src/main/resources/tessdata", "jpn_vert")
api.SetPageSegMode(tesseract.PSM_SINGLE_BLOCK_VERT_TEXT)
val pixImage = lept.pixRead("src/main/resources/image.png")
api.SetImage(pixImage)
val result = api.GetUTF8Text()
System.out.println("Parsed text: " + result?.string)
}
Prints:
Parsed text:
坊っちゃん
夏目 滞 石
If I run it from within a Spring Boot Web Socket, however, the result is not:
#SpringBootApplication
open class BootApplication
fun main(args: Array<String>) {
runApplication<BootApplication>(*args)
}
#Configuration
#EnableWebSocket
open class WebSocketConfiguration: WebSocketConfigurer {
#Bean
open fun createWebSocketContainer(): ServletServerContainerFactoryBean {
val container = ServletServerContainerFactoryBean()
container.maxBinaryMessageBufferSize = 1024000
return container
}
override fun registerWebSocketHandlers(registry: WebSocketHandlerRegistry) {
registry.addHandler(Endpoint(), "/parse").setAllowedOrigins("*")
}
}
class Endpoint: AbstractWebSocketHandler() {
#Throws(IOException::class)
override fun handleBinaryMessage(session: WebSocketSession?, message: BinaryMessage?) {
// Same code as above:
val api = tesseract.TessBaseAPI()
api.Init("src/main/resources/tessdata", "jpn_vert")
api.SetPageSegMode(tesseract.PSM_SINGLE_BLOCK_VERT_TEXT)
val pixImage = lept.pixRead("src/main/resources/image.png")
api.SetImage(pixImage)
val result = api.GetUTF8Text()
System.out.println("Parsed text:\n" + result?.string)
}
}
Prints the following when handleBinaryMessage is called:
Parsed text:
蝮翫▲縺。繧?繧?
螟冗岼 貊? 遏ウ
I ran a quick test on some English text and that worked fine, so I assume this issue is language-specific.
I'm running the Boot application with the bootRun task from the Spring Boot Gradle plugin which starts an Apache Tomcat service. My first thought is that this has something to do with the fact that the Tesseract wrapper is a JNI library and the environment it's running in (Tomcat) isn't the same. If that's the case, is there some extra configuration that needs to be done to get Tesseract to work with Spring Boot and Tomcat?
For reference, my build.gradle is as follows:
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.10'
id("org.springframework.boot") version "2.1.0.RELEASE"
}
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation group: "org.bytedeco.javacpp-presets", name: "tesseract", version: "4.0.0-rc2-1.4.3"
implementation group: "org.bytedeco.javacpp-presets", name: "tesseract", version: "4.0.0-rc2-1.4.3", classifier: "windows-x86_64"
implementation group: "org.bytedeco.javacpp-presets", name: "leptonica", version: "1.76.0-1.4.3", classifier: "windows-x86_64"
implementation group: "org.springframework.boot", name: "spring-boot", version: "2.1.0.RELEASE"
implementation group: "org.springframework.boot", name: "spring-boot-starter-web", version: "2.1.0.RELEASE"
implementation group: "org.springframework", name: "spring-websocket", version: "5.1.2.RELEASE"
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
Edit
Looks like it was an encoding issue. Java's file.encoding system property was set to UTF-8 when running from outside of Boot, but set to windows-31j when in Boot. Switching result?.string to result?.getString("UTF-8") fixed it.
I'm going to chalk this up to a bug with Bytedeco's Tesseract wrapper. I did the equivalent test with tess4j and had no problems:
val imageFile = File("src/main/resources/image.png")
val tess = Tesseract()
tess.setPageSegMode(PSM_SINGLE_BLOCK_VERT_TEXT)
tess.setLanguage("jpn_vert")
System.out.println("Parsed text:\n" + tess.doOCR(imageFile))
Gives me:
坊っちゃん
夏目 滞 石
as expected.
I've filed a ticket on their github, so hopefully this will be cleared up before long.

Object of class [org.jongo.bson.RelaxedLazyDBObject] must be an instance of class com.mongodb.BasicDBObject

I'm trying to setup tests with Spring Boot and Mongo Embedded (JHipster, Flapdoodle).
In general it works. I can see database in Robomongo with created test collections and objects (migrations using Mongobee).
But when I want to access Clients collection:
List clients = clientRepository.findAll();
It throws:
java.lang.IllegalArgumentException: Given DBObject must be a BasicDBObject! Object of class [org.jongo.bson.RelaxedLazyDBObject] must be an instance of class com.mongodb.BasicDBObject
When I run application with real Mongo instance:
./mvnw -Pdev
there are no errors even though test and dev configurations use the same Mongobee mibrations.
Spring documentation is very laconic:
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-mongo-embedded
My test configuration file application.yml is:
spring:
mongodb:
embedded:
version: 3.2.1
data:
mongodb:
host: localhost
port: 27117
database: mydb-test
I use Mongo (real instance) version v3.2.7, in configuration highest possible version of Embedded Mongo which I set is 3.2.1, maybe this could be a problem?
Maybe someone could share his configuration with example working tests?
I find my self the solution.
Problem was that I used org.jongo.Jongo instead of JHipster default com.mongodb.Db in #ChangeSet.
For some reasons Jongo doesn't work well with Embedded Mongo.
When I switched to Db, all problems has gone.
NOT WORKING:
#ChangeSet(...)
public void someChange(Jongo jongo) throws IOException {
org.jongo.MongoCollection collection = jongo.getCollection("collection");
DBObject basicDBObject = new BasicDBObject();
collection.insert(basicDBObject);
...
}
WORKING:
#ChangeSet(...)
public void someChange(Db db) throws IOException {
com.mongodb.MongoCollection collection = db.getCollection("collection");
DBObject basicDBObject = new BasicDBObject();
collection.insert(basicDBObject);
...
}

Resources