manusant / spark-swagger Goto Github PK
View Code? Open in Web Editor NEWSpark (http://sparkjava.com/) support for Swagger (https://swagger.io/)
License: Apache License 2.0
Spark (http://sparkjava.com/) support for Swagger (https://swagger.io/)
License: Apache License 2.0
Expose security definition either in code or using the static config file.
Generated swagger-ui allow users to login or specify an api / bearer token. Documentation is updated with usage example.
Code is available for various security schema definitions, but none of it is currently used.
Our endpoints require authentication. UI does not allow configuring / specifying that intent.
N/A
spark-swagger 2.0.7
com.typesafe.config.ConfigException$Missing: spark-swagger.conf: 23: No configuration setting found for key 'spark-swagger.info.externalDoc'
at com.typesafe.config.impl.SimpleConfig.findKeyOrNull(SimpleConfig.java:156)
at com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:174)
at com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:180)
at com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:180)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:188)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:193)
at com.typesafe.config.impl.SimpleConfig.getObject(SimpleConfig.java:268)
at com.typesafe.config.impl.SimpleConfig.getConfig(SimpleConfig.java:274)
at com.typesafe.config.impl.SimpleConfig.getConfig(SimpleConfig.java:41)
at io.github.manusant.ss.SparkSwagger.getInfo(SparkSwagger.java:249)
Some pojo's may contain recursive definitions. An example of this would be:
class TreeNode {
List<TreeNode> items
}
class Config {
String id,
List<TreeNode>
}
Correct processing of recursive structures
Currently processing of an endpoint returning such a structure fails with a StackOverflowError
Keep track of generated definitions and return existing definition instead of processing same definition again
Once SparkSwagger object has been constructed, swagger.setInfo() has already been called, so setting the version later doesn't accomplish anything. Should add SparkSwagger.of() method that lets you pass version in.
withRequestAsCollection sets MethodDescriptor.requestAsCollection true but SwaggerSpecBuilder.buildRequestFromType does not check isRequestAsCollection so the documentation ends up with a model of the type rather than a model of a collection of the type.
When the swagger is generated, it looks like this
And my code looks like that:
@Override
public void bind(SparkSwagger sparkSwagger) {
sparkSwagger.endpoint(endpointPath("/env"), (q, a) -> logger.debug("Received request for env Rest API"))
.get(MethodDescriptor.path(""), (req, res) -> getEnvs(res));
}
So my real path is: /env
The displayed one used by the swagger is: /env/
Is it possible to remove the '/' at the end of the path ?
The SparkSwagger conf file has to provide host info and, if the host is localhost, it also has to provide the port.
The example template file uses host = "localhost" without a port, so fails on startup
The host and port are specified when starting the Spark service, why doesn't SparkSwagger get the info from the service rather than the conf file?
When running from a Windows file system (e.g. IDE running from source) filesFromDir fails to locate any ui or ui/template files. The cause is rootPath has / as the separator whereas Files.walk returns a list with \ as the separator, so the map(path -> path.toString().replace(rootPath, "")) doesn't make any replacements. I worked around it by adding a preceding replace("\\", "/"))
, not sure if that is the best way to deal with it though :)
Here is my workaround:
public List<String> filesFromDir(String prefix, String dir) throws IOException {
String rootPath = dir.replace("file:/", "");
List<String> result;
try (Stream<Path> stream = Files.walk(Paths.get(rootPath).toAbsolutePath())) {
result = stream
.filter(path -> !Files.isDirectory(path))
.map(path -> path.toString().replace("\\", "/").replace(rootPath, ""))
.filter(name -> !name.equals(prefix) && name.startsWith(prefix))
.collect(Collectors.toList());
}
return result;
}
Here are source code for and output from a simple program that seem to show that the config file is in the specified location and can be read, but that spark-swagger can't find it or perhaps can't parse it.
/*******************************************************************************
* Copyright (c) 2017, 2018, 2019, 2020 Vehera Ltd.
* All rights reserved.
*******************************************************************************/
package uk.co.scapps.cnrm;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.github.manusant.ss.SparkSwagger;
import io.github.manusant.ss.conf.Options;
import spark.Service;
public class ConfigIt {
private final static Logger logger = LogManager.getLogger();
private static Service spark;
public static void main(String[] args) {
CNRMProperties.getDefaultProperties();
sparkSetup();
}
public static void sparkSetup() {
int port = 8081;
String sparkSwaggerConfigPath = "/home/dan/git/cnrm/CNRM/src/main/resources/";
logger.info("sparkSwaggerConfigPath:" + sparkSwaggerConfigPath);
String address = "localhost";
Options options = Options.defaultOptions().confPath(sparkSwaggerConfigPath + SparkSwagger.CONF_FILE_NAME)
.version("1.0.2").build();
logger.info("Value of options.confPath: " + options.getConfPath());
listFilesUsingJavaIO(sparkSwaggerConfigPath);
showStartOfFile(options);
spark = Service.ignite().ipAddress(address).port(port);
spark.staticFiles.externalLocation(System.getProperty("java.io.tmpdir"));
logger.info("About to run SparkSwagger.of()");
SparkSwagger.of(spark, options);
}
public static void listFilesUsingJavaIO(String dir) {
Set<String> confFiles = Stream.of(new File(dir).listFiles()).filter(file -> !file.isDirectory())
.map(File::getName).collect(Collectors.toSet());
logger.info("Files in sparkSwaggerConfigPath directory: ");
for (String fileName : confFiles) {
System.out.println(fileName);
}
}
public static void showStartOfFile(Options options) {
Scanner input = null;
try {
input = new Scanner(new File(options.getConfPath()));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
logger.info("First few lines of: " + options.getConfPath());
for (int lineNo = 0; lineNo < 5; lineNo++) {
System.out.println(input.nextLine());
}
}
}
[INFO ] 2021-12-19 20:44:57.649 [main] ConfigIt - sparkSwaggerConfigPath:/home/dan/git/cnrm/CNRM/src/main/resources/
[INFO ] 2021-12-19 20:44:57.658 [main] ConfigIt - Value of options.confPath: /home/dan/git/cnrm/CNRM/src/main/resources/spark-swagger.conf
[INFO ] 2021-12-19 20:44:57.660 [main] ConfigIt - Files in sparkSwaggerConfigPath directory:
spark-swagger.conf
[INFO ] 2021-12-19 20:44:57.664 [main] ConfigIt - First few lines of: /home/dan/git/cnrm/CNRM/src/main/resources/spark-swagger.conf
spark-swagger {
# UI related configs
theme = "MATERIAL"
deepLinking = false
[main] INFO spark.staticfiles.StaticFilesConfiguration - External StaticResourceHandler configured with folder = /tmp
[main] WARN spark.staticfiles.StaticFilesFolder - Registering external static files folder [/tmp] as [/tmp].
[INFO ] 2021-12-19 20:44:57.701 [main] ConfigIt - About to run SparkSwagger.of()
Exception in thread "main" com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'spark-swagger'
at com.typesafe.config.impl.SimpleConfig.findKeyOrNull(SimpleConfig.java:156)
at com.typesafe.config.impl.SimpleConfig.findKey(SimpleConfig.java:149)
at com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:176)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:188)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:193)
at com.typesafe.config.impl.SimpleConfig.getString(SimpleConfig.java:250)
at io.github.manusant.ss.SparkSwagger.<init>(SparkSwagger.java:45)
at io.github.manusant.ss.SparkSwagger.of(SparkSwagger.java:71)
at uk.co.scapps.cnrm.ConfigIt.sparkSetup(ConfigIt.java:45)
at uk.co.scapps.cnrm.ConfigIt.main(ConfigIt.java:27)
The error message does not say that the file is not found and might be attributed to a problem with the contents of the config file, but this second program seems to show that when the same file is loaded using the default location spark-swagger loads it without error:
/*******************************************************************************
* Copyright (c) 2017, 2018, 2019, 2020 Vehera Ltd.
* All rights reserved.
*******************************************************************************/
package uk.co.scapps.cnrm;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.github.manusant.ss.SparkSwagger;
import spark.Service;
public class NoPath {
private final static Logger logger = LogManager.getLogger();
private static Service spark;
public static void main(String[] args) {
sparkSetup();
}
public static void sparkSetup() {
spark = Service.ignite().ipAddress("192.168.1.105").port(8081);
logger.info("About to run SparkSwagger.of()");
spark.staticFiles.externalLocation(System.getProperty("java.io.tmpdir"));
SparkSwagger.of(spark);
}
}
[INFO ] 2021-12-19 20:49:08.564 [main] NoPath - About to run SparkSwagger.of()
[main] INFO spark.staticfiles.StaticFilesConfiguration - External StaticResourceHandler configured with folder = /tmp
[main] WARN spark.staticfiles.StaticFilesFolder - Registering external static files folder [/tmp] as [/tmp].
[main] WARN spark.Spark - External static file location has already been set
[Thread-0] INFO org.eclipse.jetty.util.log - Logging initialized @1306ms
[Thread-0] INFO spark.embeddedserver.jetty.EmbeddedJettyServer - == Spark has ignited ...
[Thread-0] INFO spark.embeddedserver.jetty.EmbeddedJettyServer - >> Listening on 192.168.1.105:8081
[Thread-0] INFO org.eclipse.jetty.server.Server - jetty-9.3.6.v20151106
[Thread-0] INFO org.eclipse.jetty.server.ServerConnector - Started ServerConnector@2c1ef464{HTTP/1.1,[http/1.1]}{192.168.1.105:8081}
[Thread-0] INFO org.eclipse.jetty.server.Server - Started @1442ms
A GET request works as expected, but a POST request cause a console error in the UI:
system.js:461 Error: Required parameter undefined is not provided
at index.js:1
at Array.forEach (<anonymous>)
at Object.o [as buildRequest] (index.js:1)
at actions.js:237
at utils.js:121
at bindActionCreators.js:3
at wrap-actions.js:14
at Object.r (system.js:173)
at Object.executeRequest (system.js:458)
at actions.js:276
This is the code itself:
restApi.endpoint(endpointPath("/")
.withDescription("description"), (q, a) -> {})
.get(path("/alive")
.withDescription("check connectivity")
.withGenericResponse(), (request, response) -> "OK")
.post(path("/init")
.withDescription("init")
.withRequestType(InitRequest.class)
.withGenericResponse(), (req, res) -> "OK")
Maybe because the body param is missing a name?
swagger-api/swagger-ui#965
In DefinitionsFactory#getCollectionType
, the code that determines the type for a collection field fails to recognize a bounded type, e.g., MyClass
in List<T extends MyClass>
.
Some additional checks that follow the reflection/type checks shown above might be useful in determining the type.
There is also a somewhat related issue here in line 180. A failure to decode the type will result in a default return value of String.class
, but a more appropriate default might be Object.class
.
There doesn't seem to be a way to document the header parameters. I think it might be nice to add support for this feature:
For example:
path("/hammer")
.withPathParam(pathParamDescriptor)
.withQueryParam(queryParamDescriptor)
.withHeaderParam(headerParamDescriptor)
Hi! Unlike what the name suggests, method withResponseAsCollection
in MethodDescriptor.Builder
does not result in an array in the generated swagger as the return type for the API method in which it is defined. Instead, it generates the type for the provided class and sets that base type to be the return type.
Swagger version: 1.0.0.48.
repositories {
maven {
url "https://maven.pkg.github.com/manusant/spark-swagger"
}
}
dependencies {
// Spark Framework
implementation "com.sparkjava:spark-core:2.9.4"
// Swagger
implementation "io.github.manusant:spark-swagger:1.0.0.43"
}
BUILD SUCCESSFUL in 9s
1 actionable task: 1 executed
> Task :compileJava FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
> Could not find io.github.manusant:spark-swagger:2.0.2.
Searched in the following locations:
- https://dxfeed.jfrog.io/artifactory/maven-open/io/github/manusant/spark-swagger/2.0.2/spark-swagger-2.0.2.pom
- https://repo.maven.apache.org/maven2/io/github/manusant/spark-swagger/2.0.2/spark-swagger-2.0.2.pom
- https://dl.google.com/dl/android/maven2/io/github/manusant/spark-swagger/2.0.2/spark-swagger-2.0.2.pom
- file:/Users/sassy/.m2/repository/io/github/manusant/spark-swagger/2.0.2/spark-swagger-2.0.2.pom
- s3://maven.tastyworks.com.s3.us-east-1.amazonaws.com/releases/io/github/manusant/spark-swagger/2.0.2/spark-swagger-2.0.2.pom
- s3://maven.tastyworks.com.s3.us-east-1.amazonaws.com/snapshots/io/github/manusant/spark-swagger/2.0.2/spark-swagger-2.0.2.pom
- https://github.com/manusant/spark-swagger/io/github/manusant/spark-swagger/2.0.2/spark-swagger-2.0.2.pom
Required by:
project :
I think my difficulty is related to issue #2.
I am trying to create an endpoint with path: NAME_SPACE + query to be used like this:
http://192.168.1.105:4566/cnrm/admin?action=FETCH_SETTINGS
although I would also OK with:
http://192.168.1.105:4566/cnrm/admin/?action=FETCH_SETTINGS
I want it to work with the generated UI and with an openapi-generator generated Java client library. I have been unable to find a way to make both work.
It seems that if I use "/" as the value for PATH then the generated UI won't work for the method
[qtp200800517-18] INFO spark.http.matching.MatcherFilter - The requested route [/cnrm/admin] has not been mapped in Spark for Accept: [application/json]
but the Java library generated by OpenAPI-Generator works if I omit the trailing slash from the path in my Java client code.
If, on the other hand, I use "" as the value for the path then the generated UI works but I cannot find a way to make the Java library generated by OpenAPI-Generator work.
[qtp614303351-21] INFO spark.http.matching.MatcherFilter - The requested route [/cnrm/admin/] has not been mapped in Spark for Accept: [*/*]
Perhaps the generated Java library is at fault here because it seems to add a slash to whatever path it is given. At the same time, it seems that perhaps the resolution to issue #2 may have broken compatibility with openapi-generator's java client generator.
I would appreciate your thoughts on how to proceed.
##Unable to add dependency io.github.manusant:spark-swagger:2.0.8.
After following the instructions in the Readme, I am not able to add dependency io.github.manusant:spark-swagger:2.0.8. I get error "Could not find io.github.manusant:spark-swagger:2.0.8."
Trying to add Swagger to a Spark application so that I am able to obtain the yaml/json file with all the list of endpoints. This will us to setup a Postman collection that we can use for automation testing.
-Gradle 8.0.2
-Windows10
-Java8,11,17
My application is failing on startup if I try to generate doc. I tried the demo application and it seems to be doing the same thing:
Exception in thread "main" java.io.IOException: No such file or directory
at java.base/java.io.UnixFileSystem.createFileExclusively(Native Method)
at java.base/java.io.File.createNewFile(File.java:1035)
at io.github.manusant.ss.SwaggerHammer.extractUiFolder(SwaggerHammer.java:78)
at io.github.manusant.ss.SwaggerHammer.extractUi(SwaggerHammer.java:58)
at io.github.manusant.ss.SwaggerHammer.prepareUi(SwaggerHammer.java:40)
at io.github.manusant.ss.SparkSwagger.generateDoc(SparkSwagger.java:127)
at io.github.manusant.ss.demo.ThorApi.main(ThorApi.java:27)
In both cases if I remove:
.generateDoc()
then the program start successfully.
I'm thinking I have broken something in my environment or am making some other kind of basic mistake but I haven't been able to spot it. Any thoughts? Thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.