How to parse JSON payloads with GraphQL policy?

Currently, Apigee GraphQL policy does not support parsing JSON payloads. As a result, it will raise the error "steps.graphQL.InvalidPayload" if a JSON payload is received by the policy.

Apigee has already implemented support for parsing JSON payloads in the GraphQL policy and it is planned to be released with Apigee hybrid 1.7 release.

In the meantime, if you would want to use the GraphQL policy and to process JSON payloads, you could use this approach for that purpose. I would like to thank Kurt Kanaskie for sharing an example API proxy to help me to come up with this approach.

 

1. First, use two additional policies for extracting the GraphQL query from the incoming JSON payload and removing new line characters:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables continueOnError="false" enabled="true" name="Extract-GraphQL-Query">
   <DisplayName>Extract-GraphQL-Query</DisplayName>
   <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
   <JSONPayload>
       <Variable name="query">
           <JSONPath>$.query</JSONPath>
       </Variable>
       <Variable name="variables_extracted">
           <JSONPath>$.variables</JSONPath>
       </Variable>
   </JSONPayload>
</ExtractVariables>

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Javascript continueOnError="false" enabled="true" timeLimit="200" name="JS-Remove-New-Lines">
   <DisplayName>JS-Remove-New-Lines</DisplayName>
   <Properties/>
   <ResourceURL>jsc://JS-remove-new-lines.js</ResourceURL>
</Javascript>

 

JS-remove-new-lines.js:

var query = context.getVariable("query");
var query_no_nl = query.replace(/(\r\n|\n|\r)/gm, "");
context.setVariable("query_no_nl", query_no_nl);

 

2. Create a native GraphQL query using the above extracted values and set it to the request payload:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="Create-GraphQL-Payload">
   <DisplayName>Create-GraphQL-Payload</DisplayName>
   <Set>
       <Payload contentType="application/json">query {query_no_nl}</Payload>
   </Set>
</AssignMessage>

 

3. Now, engage the GraphQL policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GraphQL name="Parse-GraphQL">
   <Source>request</Source>
   <OperationType>query</OperationType>
   <MaxDepth>4</MaxDepth>
   <MaxCount>4</MaxCount>
   <Action>parse</Action>
   <ResourceURL/>
</GraphQL>

 

4. Restore the JSON GraphQL payload:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="Set-Variables">
   <DisplayName>Set-Variables</DisplayName>
   <!-- Set variables if none where provided -->
   <AssignVariable>
       <Name>variables</Name>
       <Value>{}</Value>
       <Ref>variables_extracted</Ref>
   </AssignVariable>
   <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="Restore-JSON-GraphQL-Payload">
   <DisplayName>Restore-JSON-GraphQL-Payload</DisplayName>
   <Set>
       <Payload contentType="application/json">{"query":"{query_no_nl}","variables":{variables}}</Payload>
   </Set>
</AssignMessage>

 

Finally, the above policies need to be engaged in the API proxy endpoint's request flow as shown below:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Extract-GraphQL-Query</Name>
            </Step>
            <Step>
                <Name>JS-Remove-New-Lines</Name>
            </Step>
            <Step>
                <Name>Create-GraphQL-Payload</Name>
            </Step>
            <Step>
                <Name>Parse-GraphQL</Name>
            </Step>
            <Step>
                <Name>Set-Variables</Name>
            </Step>
            <Step>
                <Name>Restore-JSON-GraphQL-Payload</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>
    <Flows/>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <HTTPProxyConnection>
        <BasePath>/hello-graphql</BasePath>
    </HTTPProxyConnection>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

 

An example API request and response:

curl -ik --location --request POST 'https://${apigee_hybrid_hostname}/hello-graphql' \
--header 'Accept-Encoding: gzip, deflate, br' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Connection: keep-alive' \
--header 'DNT: 1' \
--header 'Origin: https://api.mocki.io' \
--data-raw '{
   "query": "{\n users {\n id\n email\n name\n }\n}\n"
}'

 

HTTP/2 200
content-type: application/json; charset=utf-8
content-length: 148
date: Fri, 11 Feb 2022 00:05:22 GMT
...
server: istio-envoy

{"data":{"users":[{"id":"Hello World","email":"Hello World","name":"Hello World"},{"id":"Hello World","email":"Hello World","name":"Hello World"}]}}

 

Additional references:

Contributors
Comments
raezorsharp
Bronze 1
Bronze 1

This used to work for GraphQL queries but it seems that a change was made and this code results in 'Unparsable GraphQL payloadcom.google.gson.JsonSyntaxException: ....' now

Version history
Last update:
‎02-10-2022 07:10 PM
Updated by: