Skip to content

Commit 820da4a

Browse files
authored
Merge pull request lowcoder-org#249 from neon-balcony/develop
feat: add special support for application/*-json content types & rm useless code
2 parents 5393dc5 + 72228ed commit 820da4a

File tree

5 files changed

+75
-66
lines changed

5 files changed

+75
-66
lines changed

server/api-service/openblocks-plugins/restApiPlugin/src/main/java/com/openblocks/plugin/restapi/RestApiExecutor.java

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,12 @@
3131
import static com.openblocks.sdk.exception.PluginCommonError.QUERY_ARGUMENT_ERROR;
3232
import static com.openblocks.sdk.exception.PluginCommonError.QUERY_EXECUTION_ERROR;
3333
import static com.openblocks.sdk.plugin.restapi.DataUtils.convertToMultiformFileValue;
34-
import static com.openblocks.sdk.plugin.restapi.DataUtils.parseJsonBody;
3534
import static com.openblocks.sdk.plugin.restapi.auth.RestApiAuthType.DIGEST_AUTH;
3635
import static com.openblocks.sdk.plugin.restapi.auth.RestApiAuthType.OAUTH2_INHERIT_FROM_LOGIN;
3736
import static com.openblocks.sdk.util.ExceptionUtils.propagateError;
3837
import static com.openblocks.sdk.util.JsonUtils.readTree;
3938
import static com.openblocks.sdk.util.JsonUtils.toJsonThrows;
40-
import static com.openblocks.sdk.util.MustacheHelper.renderMustacheJsonString;
39+
import static com.openblocks.sdk.util.MustacheHelper.renderMustacheJson;
4140
import static com.openblocks.sdk.util.MustacheHelper.renderMustacheString;
4241
import static com.openblocks.sdk.util.StreamUtils.collectList;
4342
import static org.apache.commons.collections4.MapUtils.emptyIfNull;
@@ -63,6 +62,7 @@
6362

6463
import org.apache.commons.collections4.CollectionUtils;
6564
import org.apache.commons.lang3.StringUtils;
65+
import org.apache.commons.lang3.tuple.Pair;
6666
import org.bson.internal.Base64;
6767
import org.pf4j.Extension;
6868
import org.springframework.http.HttpCookie;
@@ -85,6 +85,7 @@
8585
import com.openblocks.plugin.restapi.constants.ResponseDataType;
8686
import com.openblocks.plugin.restapi.helpers.AuthHelper;
8787
import com.openblocks.plugin.restapi.helpers.BufferingFilter;
88+
import com.openblocks.plugin.restapi.model.QueryBody;
8889
import com.openblocks.plugin.restapi.model.RestApiQueryConfig;
8990
import com.openblocks.plugin.restapi.model.RestApiQueryExecutionContext;
9091
import com.openblocks.sdk.exception.PluginException;
@@ -100,7 +101,6 @@
100101
import com.openblocks.sdk.plugin.restapi.auth.BasicAuthConfig;
101102
import com.openblocks.sdk.plugin.restapi.auth.RestApiAuthType;
102103
import com.openblocks.sdk.query.QueryVisitorContext;
103-
import com.openblocks.sdk.util.JsonUtils;
104104
import com.openblocks.sdk.webclient.WebClients;
105105

106106
import lombok.Builder;
@@ -159,18 +159,23 @@ public RestApiQueryExecutionContext buildQueryExecutionContext(RestApiDatasource
159159

160160
List<Property> updatedQueryBodyParams = renderMustacheValueForQueryBody(queryBodyParams, requestParams, contentType);
161161

162-
String updatedQueryBody;
163-
if (isJsonContentType(contentType)) {
164-
updatedQueryBody = renderMustacheJsonString(queryBody, requestParams);
162+
// string | jsonNode
163+
QueryBody updatedQueryBody;
164+
Pair<Boolean, Boolean> jsonContentType = isJsonContentType(contentType);
165+
boolean isJsonContent = jsonContentType.getLeft();
166+
Boolean isSpecialJsonContent = jsonContentType.getRight();
167+
if (isJsonContent) {
168+
updatedQueryBody = new QueryBody(renderMustacheJson(queryBody, requestParams), true, isSpecialJsonContent);
165169
} else {
166-
updatedQueryBody = renderMustacheString(queryBody, requestParams);
170+
updatedQueryBody = new QueryBody(renderMustacheString(queryBody, requestParams), false, false);
167171
}
168172

169173
Map<String, String> urlParams = buildUrlParams(datasourceUrlParams, updatedQueryParams);
170174
List<Property> bodyParams = mergeBody(datasourceBodyFormData, updatedQueryBodyParams);
171175

172176
URI uri = RestApiUriBuilder.buildUri(urlDomain, updatedQueryPath, requestParams, urlParams);
173177

178+
QueryBody mergedQueryBody = mergeBody(updatedQueryBody, datasourceBodyFormData);
174179
return RestApiQueryExecutionContext.builder()
175180
.httpMethod(httpMethod)
176181
.uri(uri)
@@ -179,7 +184,7 @@ public RestApiQueryExecutionContext buildQueryExecutionContext(RestApiDatasource
179184
.urlParams(urlParams)
180185
.bodyParams(bodyParams)
181186
.encodeParams(encodeParams)
182-
.queryBody(mergeBody(updatedQueryBody, datasourceBodyFormData, contentType))
187+
.queryBody(mergedQueryBody)
183188
.forwardCookies(forwardCookies)
184189
.forwardAllCookies(forwardAllCookies)
185190
.requestCookies(queryVisitorContext.getCookies())
@@ -206,21 +211,19 @@ private List<Property> renderMustacheValueForQueryBody(List<Property> queryBodyP
206211
}
207212

208213

209-
private String mergeBody(String queryBody, List<Property> datasourceBody, String contentType) {
210-
if (CollectionUtils.isEmpty(datasourceBody)) {
214+
private QueryBody mergeBody(QueryBody queryBody, List<Property> datasourceBody) {
215+
if (!queryBody.isJsonContent() || CollectionUtils.isEmpty(datasourceBody)) {
211216
return queryBody;
212217
}
213-
if (!isJsonContentType(contentType)) {
214-
return queryBody;
215-
}
216-
Map<String, Object> map = JsonUtils.fromJsonMap(queryBody);
217-
if (map == null) {
218+
JsonNode jsonNode = queryBody.getJsonValue();
219+
if (jsonNode instanceof ObjectNode objectNode) {
220+
for (Property property : datasourceBody) {
221+
objectNode.put(property.getKey(), property.getValue());
222+
}
218223
return queryBody;
219224
}
220-
for (Property property : datasourceBody) {
221-
map.putIfAbsent(property.getKey(), property.getValue());
222-
}
223-
return JsonUtils.toJson(map);
225+
226+
return queryBody;
224227
}
225228

226229
@Override
@@ -469,7 +472,7 @@ private Map<String, String> buildHeaders(List<Property> datasourceHeaders, List<
469472
private BodyInserter<?, ? super ClientHttpRequest> buildBodyInserter(HttpMethod httpMethod,
470473
boolean isEncodeParams,
471474
String requestContentType,
472-
String queryBody,
475+
QueryBody queryBody,
473476
List<Property> bodyFormData) {
474477

475478
if (HttpMethod.GET.equals(httpMethod)) {
@@ -480,15 +483,19 @@ private Map<String, String> buildHeaders(List<Property> datasourceHeaders, List<
480483
return BodyInserters.fromValue(new byte[0]);
481484
}
482485

483-
if (isJsonContentType(requestContentType)) {
484-
return BodyInserters.fromValue(parseJsonBody(queryBody));
486+
if (queryBody.isSpecialJson()) {
487+
return BodyInserters.fromValue(queryBody.getJsonValue().toString());
488+
}
489+
490+
if (queryBody.isJsonContent()) {
491+
return BodyInserters.fromValue(queryBody.getJsonValue());
485492
}
486493

487494
if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(requestContentType)
488495
|| MediaType.MULTIPART_FORM_DATA_VALUE.equals(requestContentType)) {
489496
return dataUtils.buildBodyInserter(bodyFormData, requestContentType, isEncodeParams);
490497
}
491-
return BodyInserters.fromValue(queryBody);
498+
return BodyInserters.fromValue(queryBody.value());
492499
}
493500

494501
private boolean isNoneContentType(String requestContentType) {

server/api-service/openblocks-plugins/restApiPlugin/src/main/java/com/openblocks/plugin/restapi/helpers/ContentTypeHelper.java

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.Set;
66

77
import org.apache.commons.lang3.StringUtils;
8+
import org.apache.commons.lang3.tuple.Pair;
89
import org.springframework.http.HttpHeaders;
910
import org.springframework.http.InvalidMediaTypeException;
1011
import org.springframework.http.MediaType;
@@ -31,10 +32,19 @@ public static boolean isPicture(MediaType contentType) {
3132
MediaType.IMAGE_PNG.equals(contentType);
3233
}
3334

34-
public static boolean isJson(MediaType contentType) {
35-
return StringUtils.equalsIgnoreCase("application", contentType.getType())
36-
&& (StringUtils.equalsIgnoreCase(contentType.getSubtype(), "json") ||
37-
StringUtils.contains(contentType.getSubtype(), "+json"));
35+
public static boolean isJson(MediaType mediaType) {
36+
return StringUtils.equalsIgnoreCase("application", mediaType.getType())
37+
&& (StringUtils.equalsIgnoreCase(mediaType.getSubtype(), "json")
38+
|| StringUtils.equals(mediaType.getSubtype(), "x-ndjson")
39+
|| StringUtils.contains(mediaType.getSubtype(), "+json")
40+
|| isSpecialJson(mediaType));
41+
}
42+
43+
/**
44+
* for this type of json, its body should be parsed as JSON but write with stringify text when sending request
45+
*/
46+
public static boolean isSpecialJson(MediaType mediaType) {
47+
return StringUtils.contains(mediaType.getSubtype(), "-json");
3848
}
3949

4050
public static String parseContentType(Map<String, String> allHeaders) {
@@ -47,7 +57,7 @@ public static String parseContentType(Map<String, String> allHeaders) {
4757
}
4858

4959
public static boolean isValidContentType(String requestContentType) {
50-
if (StringUtils.isEmpty(requestContentType)) {
60+
if (StringUtils.isBlank(requestContentType)) {
5161
return true;
5262
}
5363

@@ -60,12 +70,12 @@ public static boolean isValidContentType(String requestContentType) {
6070
return true;
6171
}
6272

63-
@SuppressWarnings("deprecation")
64-
public static boolean isJsonContentType(String requestContentType) {
65-
return MediaType.APPLICATION_JSON_VALUE.equals(requestContentType)
66-
|| MediaType.APPLICATION_JSON_UTF8_VALUE.equals(requestContentType)
67-
|| MediaType.APPLICATION_PROBLEM_JSON_VALUE.equals(requestContentType)
68-
|| MediaType.APPLICATION_PROBLEM_JSON_UTF8_VALUE.equals(requestContentType);
73+
public static Pair<Boolean, Boolean> isJsonContentType(String contentType) {
74+
if (StringUtils.isBlank(contentType)) {
75+
return Pair.of(false, false);
76+
}
77+
MediaType mediaType = MediaType.valueOf(contentType);
78+
return Pair.of(isJson(mediaType), isSpecialJson(mediaType));
6979
}
7080

7181
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.openblocks.plugin.restapi.model;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
5+
/**
6+
* value is either JsonNode or String
7+
*/
8+
public record QueryBody(Object value, boolean isJsonContent, boolean isSpecialJson) {
9+
10+
public JsonNode getJsonValue() {
11+
return (JsonNode) value;
12+
}
13+
14+
}

server/api-service/openblocks-plugins/restApiPlugin/src/main/java/com/openblocks/plugin/restapi/model/RestApiQueryExecutionContext.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class RestApiQueryExecutionContext extends QueryExecutionContext {
3232
@Setter
3333
private Map<String, String> urlParams;
3434
private List<Property> bodyParams;
35-
private String queryBody;
35+
private QueryBody queryBody;
3636
private String contentType;
3737
private boolean encodeParams;
3838

@@ -49,7 +49,7 @@ public URI getUri() {
4949
return uri;
5050
}
5151

52-
public String getQueryBody() {
52+
public QueryBody getQueryBody() {
5353
return queryBody;
5454
}
5555

server/api-service/openblocks-sdk/src/main/java/com/openblocks/sdk/plugin/restapi/DataUtils.java

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
package com.openblocks.sdk.plugin.restapi;
2020

2121
import static com.openblocks.sdk.exception.PluginCommonError.DATASOURCE_ARGUMENT_ERROR;
22-
import static com.openblocks.sdk.exception.PluginCommonError.JSON_PARSE_ERROR;
22+
import static com.openblocks.sdk.util.MustacheHelper.renderMustacheJson;
2323

2424
import java.io.UnsupportedEncodingException;
2525
import java.net.URLEncoder;
2626
import java.nio.charset.StandardCharsets;
2727
import java.util.Base64;
28+
import java.util.Collections;
2829
import java.util.List;
2930
import java.util.Map;
3031
import java.util.stream.Collectors;
@@ -43,16 +44,12 @@
4344
import com.fasterxml.jackson.databind.JsonNode;
4445
import com.fasterxml.jackson.databind.ObjectMapper;
4546
import com.google.common.collect.Streams;
46-
import com.google.gson.JsonSyntaxException;
4747
import com.openblocks.sdk.exception.PluginException;
4848
import com.openblocks.sdk.exception.ServerException;
4949
import com.openblocks.sdk.models.Property;
5050
import com.openblocks.sdk.models.RestBodyFormFileData;
5151
import com.openblocks.sdk.util.ExceptionUtils;
52-
import com.openblocks.sdk.util.MustacheHelper;
5352

54-
import net.minidev.json.parser.JSONParser;
55-
import net.minidev.json.parser.ParseException;
5653
import reactor.core.publisher.Mono;
5754

5855
public class DataUtils {
@@ -97,19 +94,13 @@ public static DataUtils getInstance() {
9794
}
9895

9996
public static Object parseJsonBody(Object body) {
100-
try {
101-
if (body instanceof String str) {
102-
if ("" == body) {
103-
return new byte[0];
104-
}
105-
Object objectFromJson = parseJsonObject(str);
106-
if (objectFromJson != null) {
107-
body = objectFromJson;
108-
}
97+
if (body instanceof String str) {
98+
if ("" == body) {
99+
return new byte[0];
109100
}
110-
} catch (JsonSyntaxException | ParseException e) {
111-
throw new PluginException(JSON_PARSE_ERROR, "JSON_PARSE_ERROR", body, "Malformed JSON: " + e.getMessage());
101+
return renderMustacheJson(str, Collections.emptyMap());
112102
}
103+
113104
return body;
114105
}
115106

@@ -190,7 +181,7 @@ private List<MultipartFormData> parseMultipartFormDataList(Property property) {
190181

191182
public static List<MultipartFormData> convertToMultiformFileValue(String fileValue, Map<String, Object> paramMap) {
192183
try {
193-
JsonNode jsonValue = MustacheHelper.renderMustacheJson(fileValue, paramMap);
184+
JsonNode jsonValue = renderMustacheJson(fileValue, paramMap);
194185
if (jsonValue.isObject()) {
195186
return List.of(parseMultipartFormData(jsonValue));
196187
}
@@ -224,17 +215,4 @@ private static MultipartFormData parseMultipartFormData(JsonNode jsonObject) {
224215
result.setName(name.asText());
225216
return result;
226217
}
227-
228-
private static Object parseJsonObject(String jsonString) throws ParseException {
229-
String trimmed = jsonString.trim();
230-
231-
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
232-
return null;
233-
}
234-
235-
// JSONParser is not thread safe!!
236-
JSONParser jsonParser = new JSONParser(JSONParser.MODE_PERMISSIVE);
237-
return jsonParser.parse(jsonString);
238-
239-
}
240218
}

0 commit comments

Comments
 (0)