Skip to content

Commit 22e4eb0

Browse files
committed
feat: add OpenAPI UI (based on @mingfang fork)
1 parent 2de7c17 commit 22e4eb0

File tree

9 files changed

+84
-15
lines changed

9 files changed

+84
-15
lines changed

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public Mono<QueryExecutionResult> executeQuery(Datasource datasource, Map<String
4747

4848
return Mono.defer(() -> {
4949
if (datasourceMetaInfoService.isJsDatasourcePlugin(datasource.getType())) {
50-
return executeByNodeJs(datasource, queryConfig, requestParams);
50+
return executeByNodeJs(datasource, queryConfig, requestParams, queryVisitorContext);
5151
}
5252
return executeLocally(datasource, queryConfig, requestParams, queryVisitorContext);
5353
})
@@ -77,11 +77,19 @@ private Mono<QueryExecutionResult> executeLocally(Datasource datasource, Map<Str
7777
});
7878
}
7979

80-
private Mono<QueryExecutionResult> executeByNodeJs(Datasource datasource, Map<String, Object> queryConfig, Map<String, Object> requestParams) {
80+
private Mono<QueryExecutionResult> executeByNodeJs(Datasource datasource, Map<String, Object> queryConfig, Map<String, Object> requestParams, QueryVisitorContext queryVisitorContext) {
8181
List<Map<String, Object>> context = requestParams.entrySet()
8282
.stream()
8383
.map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue()))
8484
.collect(Collectors.toList());
85+
86+
//forward cookies to js datasource
87+
List<Map<String, Object>> cookies = queryVisitorContext.getCookies().entrySet()
88+
.stream()
89+
.map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue()))
90+
.collect(Collectors.toList());
91+
context.addAll(cookies);
92+
8593
return datasourcePluginClient.executeQuery(datasource.getType(), queryConfig, context, datasource.getDetailConfig());
8694
}
8795
}

server/api-service/lowcoder-server/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
<groupId>org.springframework.boot</groupId>
5555
<artifactId>spring-boot-starter-webflux</artifactId>
5656
</dependency>
57+
<dependency>
58+
<groupId>org.springdoc</groupId>
59+
<artifactId>springdoc-openapi-webflux-ui</artifactId>
60+
<version>1.7.0</version>
61+
</dependency>
5762
<dependency>
5863
<groupId>io.projectreactor.tools</groupId>
5964
<artifactId>blockhound</artifactId>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.lowcoder.api;
2+
3+
import io.swagger.v3.oas.models.Components;
4+
import io.swagger.v3.oas.models.OpenAPI;
5+
import io.swagger.v3.oas.models.info.Info;
6+
import io.swagger.v3.oas.models.security.SecurityRequirement;
7+
import io.swagger.v3.oas.models.security.SecurityScheme;
8+
import io.swagger.v3.oas.models.servers.Server;
9+
import org.springframework.context.annotation.Bean;
10+
import org.springframework.context.annotation.Configuration;
11+
import org.lowcoder.sdk.config.CommonConfig;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
14+
@Configuration
15+
public class OpenAPIDocsConfiguration {
16+
@Autowired
17+
private CommonConfig commonConfig;
18+
19+
@Bean
20+
public OpenAPI customizeOpenAPI() {
21+
final String securitySchemeName = commonConfig.getCookieName();
22+
return new OpenAPI()
23+
.info(new Info()
24+
.title("Lowcoder API")
25+
.version("1.0"))
26+
.addServersItem(new Server()
27+
.url("/"))
28+
.addSecurityItem(new SecurityRequirement()
29+
.addList(securitySchemeName)).components(new Components()
30+
.addSecuritySchemes(
31+
securitySchemeName,
32+
new SecurityScheme()
33+
.name(securitySchemeName)
34+
.type(SecurityScheme.Type.APIKEY)
35+
.in(SecurityScheme.In.COOKIE)
36+
));
37+
}
38+
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/ServerApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.springframework.context.annotation.ComponentScan;
1212
import org.springframework.scheduling.annotation.EnableScheduling;
1313

14+
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
1415
import lombok.extern.slf4j.Slf4j;
1516
import reactor.blockhound.BlockHound;
1617
import reactor.core.publisher.Hooks;
@@ -22,6 +23,7 @@
2223
@ComponentScan(basePackages = "org.lowcoder.api.framework.configuration")
2324
@EnableScheduling
2425
@EnableConfigurationProperties
26+
@OpenAPIDefinition
2527
public class ServerApplication {
2628

2729
@Autowired

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/framework/security/SecurityConfig.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
126126
ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, NewUrl.QUERY_URL + "/execute"),
127127
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.MATERIAL_URL + "/**"),
128128
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.ORGANIZATION_URL + "/*/datasourceTypes"), // datasource types
129-
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.DATASOURCE_URL + "/jsDatasourcePlugins")
129+
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.DATASOURCE_URL + "/jsDatasourcePlugins"),
130+
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/api/docs/**")
130131
)
131132
.permitAll()
132133
.pathMatchers("/api/**")

server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,10 @@ common:
4848
material:
4949
mongodb-grid-fs:
5050
bucket-name: material
51+
52+
springdoc:
53+
api-docs:
54+
path: /api/docs/api-docs
55+
swagger-ui:
56+
path: /api/docs/swagger-ui
57+
paths-to-exclude: /api/v1/**

server/api-service/lowcoder-server/src/main/resources/selfhost/ce/application.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,10 @@ common:
4646
material:
4747
mongodb-grid-fs:
4848
bucket-name: material
49+
50+
springdoc:
51+
api-docs:
52+
path: /api/docs/api-docs
53+
swagger-ui:
54+
path: /api/docs/swagger-ui
55+
paths-to-exclude: /api/v1/**

server/node-service/src/plugins/openApi/index.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const dataSourceConfig = {
2525
label: "Spec URL",
2626
key: "url",
2727
type: "textInput",
28-
updatable: false,
28+
updatable: true,
2929
rules: [
3030
{
3131
required: true,
@@ -146,18 +146,11 @@ const openApiPlugin: DataSourcePlugin<ActionDataType, DataSourceDataType> = {
146146
dataSourceConfig: {
147147
...dataSourceConfig,
148148
extra: async (dataSourceConfig) => {
149-
const { url, extra } = dataSourceConfig;
150-
let spec: string = extra?.spec;
151-
let specObj: OpenAPI.Document;
152-
if (!spec) {
153-
// retrieve spec from remote only once
154-
const { spec: remoteSpec } = await retrieveSpec(url);
155-
specObj = remoteSpec;
156-
spec = JSON.stringify(remoteSpec);
157-
} else {
158-
specObj = safeJsonParse(spec);
159-
}
149+
// called whenever datasource config opens or changes
150+
const { url} = dataSourceConfig;
151+
const { spec: specObj} = await retrieveSpec(url);
160152
const extraParams = await authParamsConfig(specObj);
153+
const spec = JSON.stringify(specObj);
161154
return {
162155
data: {
163156
spec,

server/node-service/src/services/plugin.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,14 @@ export async function runPluginQuery(
211211
const plugin = getPlugin(pluginName, pluginContext);
212212
const queryConfig = await getQueryConfig(plugin, dataSourceConfig);
213213
const action = await evalToValue(queryConfig, dsl, context, dataSourceConfig);
214+
215+
//forward cookies
216+
context.forEach(({ key, value }) => {
217+
if (key in dataSourceConfig.dynamicParamsConfig) {
218+
const valueKey = `${key}.value`;
219+
dataSourceConfig.dynamicParamsConfig[valueKey] = value[0].value
220+
}
221+
})
214222
const result = await plugin.run(action, dataSourceConfig, pluginContext);
215223

216224
return {

0 commit comments

Comments
 (0)