1
votes

Given the following Lambda function:

const AWS = require('aws-sdk')
const { GraphQLClient } = require('graphql-request')

exports.handler = async (event) => {
  const endpoint = process.env.APPSYNC_URL
  const key = process.env.APPSYNC_API_KEY

  const graphQLClient = new GraphQLClient(endpoint, {
    headers: {
      'x-api-key': key,
    },
  })

  const record = event.Records.map((record) => {
    return AWS.DynamoDB.Converter.unmarshall(record.dynamodb.NewImage)
  })[0]

  console.log(record)
  
  // triggered from a stream on table update and functions as expected with the following log of record:

  // {
  //   ph: { raw: 1.5327472527472525, value: 3.5675802197802193 },
  //   temperature: { raw: 734, value: 21.693799999999996 },
  //   location: 'aiza-005',
  //   free_chlorine: { raw: 0.002686366689053088, value: -2.4983210208193416 },
  //   pressure: { raw: 971, value: -0.2099600000000006 },
  //   uuid: '56e5bb6fcba64d0292a8ffc847e137e2',
  //   coords: [ 42.230445, -83.728103 ],
  //   flow: { raw: 3.994627266621894, value: -0.02686366689053088 },
  //   timestamp: 1603726382563
  // }

  const mutation = `mutation PublishWaterQuality($input: CreateWaterQualityInput!) {
    publishWaterQuality(input: $input) {
      coords
      flow
      free_chlorine
      location
      ph
      pressure
      temperature
      timestamp
      uuid
    }
  }`
  
  let {
    coords,
    flow,
    free_chlorine,
    location,
    ph,
    pressure,
    temperature,
    timestamp,
    uuid,
  } = record
  
  const variables = {
    input: {
      coords: JSON.stringify(coords),
      flow: JSON.stringify(flow),
      free_chlorine: JSON.stringify(free_chlorine),
      location,
      ph: JSON.stringify(ph),
      pressure: JSON.stringify(pressure),
      temperature: JSON.stringify(temperature),
      timestamp,
      uuid,
    },
  }

  return data
}

...and the following associated schema:

input CreateWaterQualityInput {
    coords: AWSJSON!
    flow: AWSJSON!
    free_chlorine: AWSJSON!
    location: String!
    ph: AWSJSON!
    pressure: AWSJSON!
    temperature: AWSJSON!
    timestamp: AWSTimestamp!
    uuid: String!
} 

type WaterQuality {
    coords: AWSJSON!
    flow: AWSJSON!
    free_chlorine: AWSJSON!
    location: String!
    ph: AWSJSON!
    pressure: AWSJSON!
    temperature: AWSJSON!
    timestamp: AWSTimestamp!
    uuid: String!
}   

type Mutation {
    publishWaterQuality(input: CreateWaterQualityInput!): WaterQuality
}

...and the following local resolver attached to publishWaterQuality:

request

"payload": $util.toJson($context.args)

response

$util.toJson($context.result)

I receive the following error:

{
    "errorType": "Error",
    "errorMessage": "Expected JSON object but got STRING instead.: {\"response\":{\"data\":{\"publishWaterQuality\":null},\"errors\":[{\"path\":[\"publishWaterQuality\"],\"data\":null,\"errorType\":\"MappingTemplate\",\"errorInfo\":null,\"locations\":[{\"line\":2,\"column\":5,\"sourceName\":null}],\"message\":\"Expected JSON object but got STRING instead.\"}],\"status\":200},\"request\":{\"query\":\"mutation PublishWaterQuality($input: CreateWaterQualityInput!) {\\n    publishWaterQuality(input: $input) {\\n      coords\\n      flow\\n      free_chlorine\\n      location\\n      ph\\n      pressure\\n      temperature\\n      timestamp\\n      uuid\\n    }\\n  }\",\"variables\":{\"input\":{\"coords\":\"[42.230445,-83.728103]\",\"flow\":\"{\\\"raw\\\":3.994627266621894,\\\"value\\\":-0.02686366689053088}\",\"free_chlorine\":\"{\\\"raw\\\":0.002686366689053088,\\\"value\\\":-2.4983210208193416}\",\"location\":\"aiza-005\",\"ph\":\"{\\\"raw\\\":1.5327472527472525,\\\"value\\\":3.5675802197802193}\",\"pressure\":\"{\\\"raw\\\":971,\\\"value\\\":-0.2099600000000006}\",\"temperature\":\"{\\\"raw\\\":734,\\\"value\\\":21.693799999999996}\",\"timestamp\":1603726382563,\"uuid\":\"56e5bb6fcba64d0292a8ffc847e137e2\"}}}}",
    "response": {
        "data": {
            "publishWaterQuality": null
        },
        "errors": [
            {
                "path": [
                    "publishWaterQuality"
                ],
                "data": null,
                "errorType": "MappingTemplate",
                "errorInfo": null,
                "locations": [
                    {
                        "line": 2,
                        "column": 5,
                        "sourceName": null
                    }
                ],
                "message": "Expected JSON object but got STRING instead."
            }
        ],
        "status": 200
    },
    "request": {
        "query": "mutation PublishWaterQuality($input: CreateWaterQualityInput!) {\n    publishWaterQuality(input: $input) {\n      coords\n      flow\n      free_chlorine\n      location\n      ph\n      pressure\n      temperature\n      timestamp\n      uuid\n    }\n  }",
        "variables": {
            "input": {
                "coords": "[42.230445,-83.728103]",
                "flow": "{\"raw\":3.994627266621894,\"value\":-0.02686366689053088}",
                "free_chlorine": "{\"raw\":0.002686366689053088,\"value\":-2.4983210208193416}",
                "location": "aiza-005",
                "ph": "{\"raw\":1.5327472527472525,\"value\":3.5675802197802193}",
                "pressure": "{\"raw\":971,\"value\":-0.2099600000000006}",
                "temperature": "{\"raw\":734,\"value\":21.693799999999996}",
                "timestamp": 1603726382563,
                "uuid": "56e5bb6fcba64d0292a8ffc847e137e2"
            }
        }
    },
    "stack": [
        "Error: Expected JSON object but got STRING instead.: {\"response\":{\"data\":{\"publishWaterQuality\":null},\"errors\":[{\"path\":[\"publishWaterQuality\"],\"data\":null,\"errorType\":\"MappingTemplate\",\"errorInfo\":null,\"locations\":[{\"line\":2,\"column\":5,\"sourceName\":null}],\"message\":\"Expected JSON object but got STRING instead.\"}],\"status\":200},\"request\":{\"query\":\"mutation PublishWaterQuality($input: CreateWaterQualityInput!) {\\n    publishWaterQuality(input: $input) {\\n      coords\\n      flow\\n      free_chlorine\\n      location\\n      ph\\n      pressure\\n      temperature\\n      timestamp\\n      uuid\\n    }\\n  }\",\"variables\":{\"input\":{\"coords\":\"[42.230445,-83.728103]\",\"flow\":\"{\\\"raw\\\":3.994627266621894,\\\"value\\\":-0.02686366689053088}\",\"free_chlorine\":\"{\\\"raw\\\":0.002686366689053088,\\\"value\\\":-2.4983210208193416}\",\"location\":\"aiza-005\",\"ph\":\"{\\\"raw\\\":1.5327472527472525,\\\"value\\\":3.5675802197802193}\",\"pressure\":\"{\\\"raw\\\":971,\\\"value\\\":-0.2099600000000006}\",\"temperature\":\"{\\\"raw\\\":734,\\\"value\\\":21.693799999999996}\",\"timestamp\":1603726382563,\"uuid\":\"56e5bb6fcba64d0292a8ffc847e137e2\"}}}}",
        "    at GraphQLClient.<anonymous> (/var/task/node_modules/graphql-request/dist/index.js:172:35)",
        "    at step (/var/task/node_modules/graphql-request/dist/index.js:63:23)",
        "    at Object.next (/var/task/node_modules/graphql-request/dist/index.js:44:53)",
        "    at fulfilled (/var/task/node_modules/graphql-request/dist/index.js:35:58)",
        "    at processTicksAndRejections (internal/process/task_queues.js:97:5)"
    ]
}

Upon trying to update the variables without JSON.stringify():

const variables = {
  input: {
    coords,
    flow,
    free_chlorine,
    location,
    ph,
    pressure,
    temperature,
    timestamp,
    uuid,
  },
}

I then get the following error:

{
    "errorType": "Error",
    "errorMessage": "Variable 'coords' has an invalid value. Unable to parse [42.230445, -83.728103] as valid JSON.: {\"response\":{\"data\":null,\"errors\":[{\"path\":null,\"locations\":[{\"line\":1,\"column\":30,\"sourceName\":null}],\"message\":\"Variable 'coords' has an invalid value. Unable to parse [42.230445, -83.728103] as valid JSON.\"}],\"status\":200},\"request\":{\"query\":\"mutation PublishWaterQuality($input: CreateWaterQualityInput!) {\\n    publishWaterQuality(input: $input) {\\n      coords\\n      flow\\n      free_chlorine\\n      location\\n      ph\\n      pressure\\n      temperature\\n      timestamp\\n      uuid\\n    }\\n  }\",\"variables\":{\"input\":{\"coords\":[42.230445,-83.728103],\"flow\":{\"raw\":4,\"value\":0},\"free_chlorine\":{\"raw\":0.002686366689053088,\"value\":-2.4983210208193416},\"location\":\"aiza-005\",\"ph\":{\"raw\":1.5327472527472525,\"value\":3.5675802197802193},\"pressure\":{\"raw\":973,\"value\":-0.1956800000000003},\"temperature\":{\"raw\":734,\"value\":21.693799999999996},\"timestamp\":1603726443629,\"uuid\":\"0bed82734bb148279187a6b7bac17555\"}}}}",
    "response": {
        "data": null,
        "errors": [
            {
                "path": null,
                "locations": [
                    {
                        "line": 1,
                        "column": 30,
                        "sourceName": null
                    }
                ],
                "message": "Variable 'coords' has an invalid value. Unable to parse [42.230445, -83.728103] as valid JSON."
            }
        ],
        "status": 200
    },
    "request": {
        "query": "mutation PublishWaterQuality($input: CreateWaterQualityInput!) {\n    publishWaterQuality(input: $input) {\n      coords\n      flow\n      free_chlorine\n      location\n      ph\n      pressure\n      temperature\n      timestamp\n      uuid\n    }\n  }",
        "variables": {
            "input": {
                "coords": [
                    42.230445,
                    -83.728103
                ],
                "flow": {
                    "raw": 4,
                    "value": 0
                },
                "free_chlorine": {
                    "raw": 0.002686366689053088,
                    "value": -2.4983210208193416
                },
                "location": "aiza-005",
                "ph": {
                    "raw": 1.5327472527472525,
                    "value": 3.5675802197802193
                },
                "pressure": {
                    "raw": 973,
                    "value": -0.1956800000000003
                },
                "temperature": {
                    "raw": 734,
                    "value": 21.693799999999996
                },
                "timestamp": 1603726443629,
                "uuid": "0bed82734bb148279187a6b7bac17555"
            }
        }
    },
    "stack": [
        "Error: Variable 'coords' has an invalid value. Unable to parse [42.230445, -83.728103] as valid JSON.: {\"response\":{\"data\":null,\"errors\":[{\"path\":null,\"locations\":[{\"line\":1,\"column\":30,\"sourceName\":null}],\"message\":\"Variable 'coords' has an invalid value. Unable to parse [42.230445, -83.728103] as valid JSON.\"}],\"status\":200},\"request\":{\"query\":\"mutation PublishWaterQuality($input: CreateWaterQualityInput!) {\\n    publishWaterQuality(input: $input) {\\n      coords\\n      flow\\n      free_chlorine\\n      location\\n      ph\\n      pressure\\n      temperature\\n      timestamp\\n      uuid\\n    }\\n  }\",\"variables\":{\"input\":{\"coords\":[42.230445,-83.728103],\"flow\":{\"raw\":4,\"value\":0},\"free_chlorine\":{\"raw\":0.002686366689053088,\"value\":-2.4983210208193416},\"location\":\"aiza-005\",\"ph\":{\"raw\":1.5327472527472525,\"value\":3.5675802197802193},\"pressure\":{\"raw\":973,\"value\":-0.1956800000000003},\"temperature\":{\"raw\":734,\"value\":21.693799999999996},\"timestamp\":1603726443629,\"uuid\":\"0bed82734bb148279187a6b7bac17555\"}}}}",
        "    at GraphQLClient.<anonymous> (/var/task/node_modules/graphql-request/dist/index.js:172:35)",
        "    at step (/var/task/node_modules/graphql-request/dist/index.js:63:23)",
        "    at Object.next (/var/task/node_modules/graphql-request/dist/index.js:44:53)",
        "    at fulfilled (/var/task/node_modules/graphql-request/dist/index.js:35:58)",
        "    at processTicksAndRejections (internal/process/task_queues.js:97:5)"
    ]
}

I have also tried this via console with the following query variables:

mutation MyMutation($coords: AWSJSON!, $flow: AWSJSON!, $free_chlorine: AWSJSON!, $location: String!, $ph: AWSJSON!, $pressure: AWSJSON!, $temperature: AWSJSON!, $timestamp: AWSTimestamp!, $uuid: String!) {
  publishWaterQuality(input: {coords: $coords, flow: $flow, free_chlorine: $free_chlorine, location: $location, ph: $ph, pressure: $pressure, temperature: $temperature, timestamp: $timestamp, uuid: $uuid}) {
    coords
    flow
    free_chlorine
    location
    ph
    pressure
    temperature
    timestamp
    uuid
  }
}

{
  "coords": "[42.230445,-83.728103]",
  "flow": "{\"raw\":3.994627266621894,\"value\":-0.02686366689053088}",
  "free_chlorine": "{\"raw\":0.008059100067159264,\"value\":-2.4949630624580257}",
  "location": "aiza-001",
  "ph": "{\"raw\":1.506959706959707,\"value\":3.475776556776556}",
  "pressure": "{\"raw\":975,\"value\":-0.1814}",
  "temperature": "{\"raw\":726,\"value\":20.9122}",
  "timestamp": 1603703530407,
  "uuid": "74b5b1271ccd43639d5ce0512fa62f02"
}

same type of error:

{
  "data": {
    "publishWaterQuality": null
  },
  "errors": [
    {
      "path": [
        "publishWaterQuality"
      ],
      "data": null,
      "errorType": "MappingTemplate",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "Expected JSON object but got STRING instead."
    }
  ]
}

What am I missing here? The list query works fine with these schema types, so what is incorrect about my mutation and or scheme type combination, or is the resolver setup incorrectly?

^ thats really just one question asking what am I doing wrong?

As always any and all direction and feedback is appreciated, so thank you in advance!

EDIT UPDATE 1

///////// TL;DR ////////// updating the resolver to the following gets me much closer:

{
    "version": "2017-02-28",
    "payload": {
        "coords": "$context.arguments.input.coords",
        "flow": "$context.arguments.input.flow",
        "free_chlorine": "$context.arguments.input.free_chlorine",
        "location": "$context.arguments.input.location",
        "ph": "$context.arguments.input.ph",
        "pressure": "$context.arguments.input.pressure",
        "temperature": "$context.arguments.input.temperature",
        "timestamp": 1603726443629,
        "uuid": "$context.arguments.input.uuid"
    }
}

however the response is not valid JSON

{
  "data": {
    "publishWaterQuality": {
      "coords": "\"[42.230445, -83.728103]\"",
      "flow": "\"{raw=3.994627266621894, value=-0.02686366689053088}\"",
      "free_chlorine": "\"{raw=0.008059100067159264, value=-2.4949630624580257}\"",
      "location": "aiza-001",
      "ph": "\"{raw=1.506959706959707, value=3.475776556776556}\"",
      "pressure": "\"{raw=975, value=-0.1814}\"",
      "temperature": "\"{raw=726, value=20.9122}\"",
      "timestamp": 1603726443629,
      "uuid": "74b5b1271ccd43639d5ce0512fa62f02"
    }
  }
}

changing the resolver argument as such:

"$util.toJson(${context.arguments.input.free_chlorine})"

results in an error:

"message": "Unexpected character ('r' (code 114)): was expecting comma to separate Object entries\n at [Source: (String)\"{\n    \"version\": \"2017-02-28\",\n    \"payload\": {\n    \t\"coords\": \"[42.230445, -83.728103]\",\n        \"flow\": \"{\"raw\":3.994627266621894,\"value\":-0.02686366689053088}\",\n        \"free_chlorine\": \"{raw=0.008059100067159264, value=-2.4949630624580257}\",\n        \"location\": \"aiza-001\",\n        \"ph\": \"{raw=1.506959706959707, value=3.475776556776556}\",\n        \"pressure\": \"{raw=975, value=-0.1814}\",\n        \"temperature\": \"{raw=726, value=20.9122}\",\n        \"timestamp\": 1603726443629,\n        \"uuid\": \"74b5\"[truncated 110 chars]; line: 5, column: 21]"

EDIT UPDATE 2

resolvers that appear to be working correctly:

request:

{
    "version": "2017-02-28",
    "payload": $utils.toJson($context.arguments.input)
}

response:

{
    "coords": $context.arguments.input.coords,
    "flow": $utils.toJson($context.arguments.input.flow),
    "free_chlorine": $utils.toJson($context.arguments.input.free_chlorine),
    "location": $utils.toJson($context.arguments.input.location),
    "ph": $utils.toJson($context.arguments.input.ph),
    "pressure": $utils.toJson($context.arguments.input.pressure),
    "temperature": $utils.toJson($context.arguments.input.temperature),
    "timestamp": 1603726443629,
    "uuid": "$context.arguments.input.uuid"
}

with the following results:

{
  "data": {
    "publishWaterQuality": {
      "uuid": "74b5b1271ccd43639d5ce0512fa62f02",
      "timestamp": 1603726443629,
      "temperature": "{\"raw\":726,\"value\":20.9122}",
      "pressure": "{\"raw\":975,\"value\":-0.1814}",
      "ph": "{\"raw\":1.506959706959707,\"value\":3.475776556776556}",
      "location": "aiza-001",
      "free_chlorine": "{\"raw\":0.008059100067159264,\"value\":-2.4949630624580257}",
      "flow": "{\"raw\":3.994627266621894,\"value\":-0.02686366689053088}",
      "coords": "[42.230445,-83.728103]"
    }
  }
}
1
Have you tried $util.parseJson($ctx.result) instead of $utils.toJson($ctx.result) in your resolver? - Myz
I have now, with both versions of the variables. Same errors. - studiobrain
I think what you missing here is how you accessing the data. Since ctx.result contains other things too which are not expected by your resolver. You can try $util.parseJson($ctx.result.data).get("publishWaterQuality") - Myz
While I do now suspect the resolver is the issue, the above did not resolve. Im trying a few different resolvers now. - studiobrain

1 Answers

1
votes

The solution was given in the EDIT UPDATE 2

I am going to leave this for anyone facing similar issues, or if anyone would like to add a better solution.