Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 22e4eb0

Browse files
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, QueryVisitorContextqueryVisitorContext) {
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)

AltStyle によって変換されたページ (->オリジナル) /