No API definition provided. - openApi - springdoc - openapi

I have a simple boot application where I have added open api swagger dependency
springdoc-openapi-ui
along with these properties
springdoc.swagger-ui.disable-swagger-default-url=true
springdoc.swagger-ui.configUrl=/v3/api-docs/swagger-config
springdoc.swagger-ui.path=/swagger-ui.html
I am getting these error (when calling http://localhost:8080/swagger-ui/index.html):
No API definition provided.
this is my controller :
#RestController
public class HelloWorld {
#GetMapping("sayHi")
public String sayHi(){
return "Hi Beno";
}
}
Any idea ?

When using a different endpoint to serve the OpenAPI Config, you'll need to set two properties
// This will set UI to fetch the config's URL from "somePath"
springdoc.swagger-ui.configUrl=somePath
// You also need to serve the config file from the endpoint at "somePath"
springdoc.api-docs.path=somePath

Related

Failed to load API definition Fetch Error, when deployed but fine on localhost

I am upgrading my api from netcore2.1 to 3.1
When I run on localhost the UI works fine.
When I deploy via Azure DevOps and go to the myapplication/myapi/swagger.html url I get
Failed to load API definition
Fetch Error
Service Unavailable /myapi/swagger/v1/swagger/json
Yet I can see the json at
myapplication/myapi/swagger/v1/swagger.json
I have the following
public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app)
{
app.UseSwagger(c =>
c.RouteTemplate = "myapi/swagger/{documentName}/swagger.json"
);
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/myapi/swagger/v1/swagger.json", "Versioned API v1.0");
c.RoutePrefix = "myapi/swagger";
});
return app;
}
I am using
Swashbuckle.AspNetCore (5.2.0)
I found the following worked.
public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app)
{
app.UseSwagger(c =>
c.RouteTemplate = "myapi/{documentName}/swagger.json"
);
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("./v1/swagger.json", "Versioned API v1.0");
c.RoutePrefix = "myapi";
});
return app;
}
The docs state
If using directories with IIS or a reverse proxy, set the Swagger
endpoint to a relative path using the ./ prefix. For example,
./swagger/v1/swagger.json. Using /swagger/v1/swagger.json instructs
the app to look for the JSON file at the true root of the URL (plus
the route prefix, if used). For example, use
http://localhost://swagger/v1/swagger.json instead
of
http://localhost:///swagger/v1/swagger.json.
However unfortunately my solution doesn't work with Autorest.
Thus I asked another question

Camel Restlet - Context Path Ambiquity

I have Spring Boot Camel application where rest apis are exposed using camel-restlet
Sample route
#Component
public class AppRoute extends RouteBuilder{
public void configure(CamelContext context){
from("restlet:employee?restletMethods=GET").log("${body}");
}
}
The App runs perfect ( spring-boot:run ). but am unable to locate under which path the API is exposed. Log has no information.
Every API i hit returns 404. Log shows the route has been started. Under which path is it running. And how do I change it?
Note: Please dont suggest any XML based configuration. Anything that I can put under #Configuration would be perfect
I would go with the Rest DSL which is supported by the camel-restlet component like this
restConfiguration().component("restlet").port(8080);
rest("/rest")
.get("employee")
.route().log("${body}")
.endRest();
And this route will listen to the following url
http://localhost:8080/rest/employee
EDIT:
I guess you could do something like without using the Rest DSL
String host = InetAddress.getLocalHost().getHostName();
from("restlet:http://" + host + contextPath + "/employee?restletMethods=GET").log("${body}")
The port and context path are configurable with the following properties
camel.component.restlet.port=8686
server.servlet.context-path=/my-path
The context path can be injected in the routeBuilder with
#Value("${server.servlet.context-path}")
private String contextPath;
According to the documentation, the format of the URI in a restlet endpoint definition should be the following:
restlet:restletUrl[?options]
Where restletUrl should have the following format:
protocol://hostname[:port][/resourcePattern]
So in your case you could define the URI in the following way:
from("restlet:http://localhost/employee?restletMethods=GET")
This should make the endpoint available under the following URL:
http://localhost/employee
Which you can test e.g. in a web browser.
Use the first of the three configuration methods described here:
https://restlet.com/open-source/documentation/javadocs/2.0/jee/ext/org/restlet/ext/servlet/ServerServlet.html
You should be able to customize it using the Component:
https://restlet.com/open-source/documentation/javadocs/2.0/jee/api/org/restlet/Component.html?is-external=true
See in particular setServers() methods (or XML equivalent) to change the hostname and port.

"Secret id missing" error while connecting to Vault using Spring cloud vault

I am trying to connect to spring vault using role based authentication (spring boot project).
As per documentation, I should be able to connect to spring vault only using approle (pull mode). However, I am getting secrect-id missing exception on application start up.
http://cloud.spring.io/spring-cloud-vault/single/spring-cloud-vault.html#_approle_authentication
When I pass, secret-id also, I am able to connect and properties/values are getting correctly autowired.
Is there any way I can connect with vault using "token + role/role-id" and spring generate secret-id for me automatically at run time using mentioned info.
spring.cloud.vault:
scheme: http
host: <host url>
port: 80
token : <token>
generic.application-name: vault/abc/pqr/test
generic.backend: <some value>
generic.default-context: vault/abc/pqr/test
token: <security token>
authentication: approle
app-role:
role-id: <role-id>
POM:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-vault-starter-config</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</dependency>
Please let me know in case any other info is required.
Update
#mp911de, I tried as per your suggestion, however spring-cloud-vault is picking properties set in bootstrap.yml and not one set inside "onApplicationEvent" and thus solution is not working. I tried setting property by "System.setProperty" method but that event didn't worked.
However, if I am setting properties in main before run method, it is working as expected. But I need to load application.properties first (need to pick some configuration from there) and thus don't want to write logic there.
Is there anything wrong in my approach ??
#Component public class LoadVaultProperties implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
private RestTemplate restTemplate = new RestTemplate();
#Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
try {
String roleId = getRoleIdForRole(event); //helper method
String secretId = getSecretIdForRoleId(event); //helper method
Properties properties = new Properties();
properties.put("spring.cloud.vault.app-role.secret-id", secretId);
properties.put("spring.cloud.vault.app-role.role-id", roleId);
event.getEnvironment().getPropertySources().addFirst(new PropertiesPropertySource(
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME, properties));
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
Spring Vault's AppRole authentication supports two modes but not the pull mode:
Push mode in which you need to supply the secret_id
Authenticating without a secret_id by just passing role_id. This mode requires the role to be created without requiring the secret_id by setting bind_secret_id=false on role creation
Pull mode as mention in the Vault documentation requires the client to know about the secret_id, obtained from a wrapped response. Spring Vault does not fetch a wrapped secret_id but I think that would be a decent enhancement.
Update: Setting system properties before application start:
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
System.setProperty("spring.cloud.vault.app-role.role-id", "…");
System.setProperty("spring.cloud.vault.app-role.secret-id", "…");
SpringApplication.run(MyApplication.class, args);
}
References:
Vault documentation on AppRole creation
Spring Cloud Vault documentation on AppRole authentication.

Configuring Spring Cloud Vault Config to pull from a location other than /secret

I am currently integrating Spring Cloud Vault Config into a Spring Boot application. From the home page:
Spring Cloud Vault Config reads config properties from Vaults using the application name and active profiles:
/secret/{application}/{profile}
/secret/{application}
/secret/{default-context}/{profile}
/secret/{default-context}
I would like to instead provide my own location from which to pull properties from Vault which does not start with /secret (e.g. /deployments/prod). I've been looking through the reference documentation but I haven't found anyway to specify this -- is it possible?
I was able to use the Generic Backend properties to massage the paths into what I was looking for. Something like:
spring.cloud.vault:
generic:
enabled: true
backend: deployments
profile-separator: '/'
default-context: prod
application-name: my-app
This will also unfortunately pickup Vault locations like deployments/my-app and deployments/prod/activeProfile so be careful not to have any properties in these locations that you don't want to be picked up.
It looks like there is a desire (and an implementation) to allow for these paths to be specified more programmatically.
It should be done this way.
Have a Configuration class
#Configuration
public class VaultConfiguration {
#Bean
public VaultConfigurer configurer() {
return new VaultConfigurer() {
#Override
public void addSecretBackends(SecretBackendConfigurer configurer) {
configurer.add("secret/my-app/path-1");
configurer.add("secret/my-app/path-2");
configurer.registerDefaultGenericSecretBackends(false);
}
};
}
}
This way you can scan your secrets placed in custom path
Regards
Arun
I solved the same problem in my Kotlin project. But it works in Java too.
Problem
I wanted to specify vault paths in yaml config, so i ended up with the following solution, that allows you to specify paths directly in bootstrap.yml using clear syntax, as:
spring:
cloud:
vault:
paths: "secret/your-app"
Solution:
Create VaultConfig class in your project, with the following content:
package com.your.app.configuration
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.cloud.vault.config.VaultConfigurer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
#Configuration
#ConditionalOnProperty(
prefix = "spring.cloud.vault", value = ["paths"],
matchIfMissing = false
)
class VaultConfig {
#Value("\${spring.cloud.vault.paths}")
private lateinit var paths: List<String>
#Bean
fun configurer(): VaultConfigurer {
return VaultConfigurer { configurer ->
paths.forEach {
configurer.add(it)
}
configurer.registerDefaultGenericSecretBackends(false)
configurer.registerDefaultDiscoveredSecretBackends(false)
}
}
}
Create spring.factories file in src/main/resources/META-INF/spring.factories with a content:
org.springframework.cloud.bootstrap.BootstrapConfiguration=com.your.app.configuration.VaultConfig
Don't forget to specify valid reference to your config instead of
com.your.app.configuration.VaultConfig
spring.factories allows your VaultConfig
happen in the bootstrap context, as documentation says.
Now you can specify desired paths in your bootstrap.yml, as follows:
spring:
cloud:
vault:
paths:
- "secret/application"
- "secret/your-app"
And it should work.

change default /webservices path for Apache CXF SOAP service

I'm using tomEE 1.7.1 with Apache CXF 2.6.14 inside.
I have a component that serves a WSDL first web service:
#Stateless
#WebService(
endpointInterface = "com.mycompany.SecurityTokenServiceWS",
targetNamespace = "http://sts.mycompany/wsdl/",
serviceName = "SecurityTokenService",
portName = "TokenService")
#SOAPBinding(style = SOAPBinding.Style.RPC, use = SOAPBinding.Use.LITERAL)
public class TokenService implements SecurityTokenServiceWS {
//service methods
}
When I deploy the web app, I see this log:
Jan 30, 2015 12:47:22 PM org.apache.openejb.server.webservices.WsService deployApp
INFORMATION: Webservice(wsdl=http://localhost:8080//webservices/TokenService, qname={http://sts.mycompany.com/wsdl/}SecurityTokenService) --> Ejb(id=TokenService)
In result the web service is available on: http://localhost:8080/webservices/TokenService.
What I like to have is that the service runs directly on: http://localhost:8080/TokenService.
I have no idea where the "webservices" path element comes from. It isn't in the WSDL and not in any configuration file. My web application runs directly under the context path / (ROOT).
Is there a magic CXF servlet that is bonded to /webservices? How can I change this behavior?
this comes from TomEE which uses subcontext webservices by default.
This sample shows how to change it https://git-wip-us.apache.org/repos/asf?p=tomee.git;a=tree;f=examples/change-jaxws-url;h=2f88382bd4f925ec27c7305e74d361c8baf46a92;hb=ebe63371a22709a50e79c42206b5e9a0fd8946cc (the interesting file is https://git-wip-us.apache.org/repos/asf?p=tomee.git;a=blob;f=examples/change-jaxws-url/src/main/resources/META-INF/openejb-jar.xml;h=6c0ba44b14eb2e67a550c65d890d325c8bf409b7;hb=ebe63371a22709a50e79c42206b5e9a0fd8946cc)
Note: if you just want to rename /webservices you can set in conf/system.properties tomee.jaxws.subcontext=/myothersubcontext
PS: if you go with openejb-jar.xml solution note there is the equivalent for openejb-jar.xml 1.1 which is just the property openejb.webservice.deployment.address in your ejb-deployment properties
To change the publishiing address you need to change endpoint configuration. For now I guess you have no configuration and all is default. You need to create file service.xml (any name) and provide path to it either using web.xml CXFServlet init-parameter "config-location" or using Spring.
Here is the file contents http://cxf.apache.org/docs/jax-ws-configuration.html
And here is an example how to do it with spring http://cxf.apache.org/docs/writing-a-service-with-spring.html