Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,19 @@ public GraphQLController(Builder builder) {
* curl --location -g --request GET 'http://localhost:8083/graphql?query={me{myVariable: $someValue}{id+name+friends{name}}}&variables={"id" : 1}'
* </code>
*
* @param arguments the request arguments
* @param query GraphQL query
* @param variables a JSON-encoded string like <code>{ "myVariable": "someValue", ... }</code>
* @param arguments the request arguments
* @param query GraphQL query
* @param operationName optional operation name for named operations
* @param variables a JSON-encoded string like
* <code>{ "myVariable": "someValue", ... }</code>
* @return the result
*/
@SuppressWarnings("unchecked")
@DoGet("/graphql")
public Object doGet(
RequestArguments arguments,
@RequestParam("query") String query,
@RequestParam("operationName") String operationName,
@RequestParam("variables") String variables
) {
Map<String, Object> variableMap = Collections.emptyMap();
Expand All @@ -92,7 +95,7 @@ public Object doGet(
);
}
}
return fetch(arguments, query, variableMap);
return fetch(arguments, query, operationName, variableMap);
}

/**
Expand All @@ -119,6 +122,7 @@ public Object doPost(
return fetch(
arguments,
request.getQuery(),
request.getOperationName(),
request.getVariables()
);
}
Expand All @@ -127,9 +131,11 @@ public Object doPost(
private Object fetch(
RequestArguments arguments,
String query,
String operationName,
Map<String, Object> variables
) {
GraphQLSchema schema = schemaParser.parseQuery(query, variables);
GraphQLSchema schema = schemaParser
.parseQuery(query, operationName, variables);
List<GraphQLQueryDefinition> queryDefinitions = schema
.getQueryDefinitions();
Map<String, Object> answer = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@Setter
public class GraphQLRequest {
private String query;
private String operationName;
private Map<String, Object> variables;

public Map<String, Object> getVariables() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Map;

import static com.tvd12.ezyfox.io.EzyStrings.EMPTY_STRING;
import static com.tvd12.ezyfox.io.EzyStrings.isNotBlank;

@AllArgsConstructor
public final class GraphQLSchemaParser {
Expand All @@ -23,6 +24,28 @@ public final class GraphQLSchemaParser {
private static final String VARIABLE_PLACEHOLDER_FIELD =
"__ezyhttp_graphql_variable__";

public GraphQLSchema parseQuery(
String queryToParse,
String operationName,
Map<String, Object> variables
) {
if (!isNotBlank(operationName)) {
return parseQuery(queryToParse, variables);
}
String standardized = standardizeKeepOperationNames(queryToParse);
String selectionSet = extractNamedOperation(standardized, operationName);
if (selectionSet == null) {
throw new GraphQLObjectMapperException(
Collections.singletonList(
GraphQLError.builder()
.message("unknown operation named: " + operationName)
.build()
)
);
}
return parseQuery(selectionSet, variables);
}

@SuppressWarnings({"unchecked", "MethodLength"})
public GraphQLSchema parseQuery(
String queryToParse,
Expand Down Expand Up @@ -77,8 +100,6 @@ public GraphQLSchema parseQuery(
);
replaceVariablePlaceholders(argumentMap, variables);
childBuilder.arguments(argumentMap);
} catch (GraphQLObjectMapperException e) {
throw e;
} catch (Exception e) {
throw new GraphQLObjectMapperException(
Collections.singletonList(
Expand Down Expand Up @@ -176,6 +197,42 @@ public GraphQLSchema parseQuery(
return schemaBuilder.build();
}

private String extractNamedOperation(
String standardizedQuery,
String operationName
) {
int nameIdx = standardizedQuery.indexOf(operationName);
while (nameIdx >= 0) {
boolean validPrefix = nameIdx == 0
|| !isGraphQLNameChar(standardizedQuery.charAt(nameIdx - 1));
int afterName = nameIdx + operationName.length();
boolean validSuffix = afterName >= standardizedQuery.length()
|| !isGraphQLNameChar(standardizedQuery.charAt(afterName));
if (validPrefix && validSuffix) {
int braceStart = afterName;
while (braceStart < standardizedQuery.length()
&& standardizedQuery.charAt(braceStart) != '{') {
braceStart++;
}
if (braceStart < standardizedQuery.length()) {
int depth = 0;
for (int i = braceStart; i < standardizedQuery.length(); i++) {
char c = standardizedQuery.charAt(i);
if (c == '{') {
depth++;
} else if (c == '}') {
if (--depth == 0) {
return standardizedQuery.substring(braceStart, i + 1);
}
}
}
}
}
nameIdx = standardizedQuery.indexOf(operationName, nameIdx + 1);
}
return null;
}

/**
* Remove redundant '\t', '\n', '+', ',', ' ' in query.
*
Expand All @@ -186,14 +243,22 @@ private String standardize(String query) {
if (query == null) {
return EMPTY_STRING;
}
String trimedQuery = query.trim();
StringBuilder forwardStandard = forwardStandardize(trimedQuery);
String trimmedQuery = query.trim();
StringBuilder forwardStandard = forwardStandardize(trimmedQuery);
StringBuilder backwardStandard = backwardStandardize(
forwardStandard.toString()
);
return removeQueryPrefix(backwardStandard.toString());
}

private String standardizeKeepOperationNames(String query) {
if (query == null) {
return EMPTY_STRING;
}
StringBuilder forwardStandard = forwardStandardize(query.trim());
return backwardStandardize(forwardStandard.toString()).toString();
}

private StringBuilder forwardStandardize(String query) {
int queryLength = query.length();
StringBuilder answer = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void test() throws Exception {
// when
Object meResult = controller.doPost(arguments, meRequest);
Throwable e = Asserts.assertThrows(() ->
controller.doGet(arguments, heroQuery, null)
controller.doGet(arguments, heroQuery, null, null)
);

// then
Expand Down Expand Up @@ -234,7 +234,7 @@ public void getAllFriendFields() {
// when
Object meResult = controller.doPost(arguments, meRequest);
Throwable e = Asserts.assertThrows(() ->
controller.doGet(arguments, heroQuery, null)
controller.doGet(arguments, heroQuery, null, null)
);

// then
Expand Down Expand Up @@ -290,7 +290,7 @@ public void testFetcherNotFoundException() {
String heroQuery = "{hero}";

// when
Throwable e = Asserts.assertThrows(() -> controller.doGet(arguments, heroQuery, null));
Throwable e = Asserts.assertThrows(() -> controller.doGet(arguments, heroQuery, null, null));

// then
Asserts.assertEqualsType(e, GraphQLFetcherException.class);
Expand Down Expand Up @@ -338,7 +338,7 @@ public void testInterceptorFalse() {
String heroQuery = "{hero}";

// when
Throwable e = Asserts.assertThrows(() -> controller.doGet(arguments, heroQuery, null));
Throwable e = Asserts.assertThrows(() -> controller.doGet(arguments, heroQuery, null, null));

// then
Asserts.assertEqualsType(e, GraphQLFetcherException.class);
Expand Down Expand Up @@ -413,7 +413,7 @@ public void testQueryWithVariables() {

// when
Throwable e = Asserts.assertThrows(() ->
controller.doGet(arguments, welcomeQuery, variablesString)
controller.doGet(arguments, welcomeQuery, null, variablesString)
);

// then
Expand Down Expand Up @@ -478,8 +478,8 @@ public void testQueryWithNullVariableType() {
String fooQuery = "{foo{value(value:$value){*}}}";

// when
Object fooResult1 = controller.doGet(arguments, fooQuery, "{\"value\": \"Bar\"}");
Object fooResult2 = controller.doGet(arguments, fooQuery, null);
Object fooResult1 = controller.doGet(arguments, fooQuery, null, "{\"value\": \"Bar\"}");
Object fooResult2 = controller.doGet(arguments, fooQuery, null, null);

// then
Asserts.assertEquals(fooResult1.toString(), "{data={foo={value={bar=Bar}}}}");
Expand Down Expand Up @@ -609,7 +609,7 @@ public void doGetTestException() {
String heroQuery = "{hero}";

// when
Throwable e = Asserts.assertThrows(() -> controller.doGet(arguments, heroQuery, "abc"));
Throwable e = Asserts.assertThrows(() -> controller.doGet(arguments, heroQuery, null, "abc"));

// then
Asserts.assertEqualsType(e, GraphQLObjectMapperException.class);
Expand Down
Loading
Loading