Lambda function isn't sending update mutation to Appsync subscription

0

I've created a python Lambda function that is triggered from DynamoDB update stream, which then sends a mutation query to a GraphQL endpoint in AppSync. I'm using a None datasource revolver for the mutation in AppSync and my Lambda function returns a 200 OK GraphQL response when testing, but my subscription in my Android app seems to be waiting forever and doesn't receive a mutation. I'm using an API Key for authentication and my role is given all the permissions for testing purposes. The subscription in AppSync doesn't have a resolver at all and I can't seem to test the queries in the console because of the None data source. I'm not sure how to solve this problem and could really use some help!

subscription from subscriptions.grapql:

subscription OnUpdateParkingData {
  onUpdateParkingData {
    ParkingLotName
    availableSpaces
    capacity
  }
}

subscription and mutation from schema.graphql:

type Subscription {
  onUpdateParkingData: ParkingData @aws_subscribe(mutations : ["updateParkingData"])
}

type Mutation {
  updateParkingData(input: UpdateParkingDataInput!): ParkingData
}

mutation from mutations.graphql:

mutation UpdateParkingData($input: UpdateParkingDataInput!) {
  updateParkingData(input: $input) {
    ParkingLotName
    availableSpaces
    capacity
  }
}

lambda function:

import json
from botocore.vendored import requests

GRAPHQL_URL = 'https://****.appsync-api.us-east-1.amazonaws.com/graphql'

GRAPHQL_API_KEY = "*****"

HEADERS = {
    "Content-Type": "application/json",
    "X-Api-Key":GRAPHQL_API_KEY
}



def lambda_handler(event, context):
    for record in event['Records']:
        if (record['eventName'] == "MODIFY"):
            parkingLotName = json.dumps(record['dynamodb']['NewImage']['ParkingLotName']['S'])
            capacity = json.dumps(record['dynamodb']['NewImage']['capacity']['S'])
            availableSpaces = json.dumps(record['dynamodb']['NewImage']['availableSpaces']['S'])
            
            res = {}
            json_string = "{{ParkingLotName: {}, availableSpaces: {}, capacity: {}}}".format(parkingLotName, availableSpaces, capacity)
            mutation_string = "mutation updateParkingData {{updateParkingData(input: {}){{ParkingLotName, availableSpaces, capacity}}}}".format(json_string)

            data = {"query": 
                mutation_string}

            try:
                res = requests.post(
                    GRAPHQL_URL,
                    headers=HEADERS,
                    data=json.dumps(data)
                )

            except Exception as e:
                print('error: ', e)
        
    return 'Successfully processed {} records.'.format(len(event['Records']))

Edited by: dflgal on Aug 27, 2019 12:55 PM

asked 5 years ago1.7K views
6 Answers
0

Looks like there is an issue with the way you are constructing the request. I made a similar schema to yours, and the HTTP request content should look like this:

{"query":"mutation updateParkingData {updateParkingData(input: {ParkingLotName: \"test\", availableSpaces: 1, capacity: 1}){name, spaces, capacity}}","variables":null,"operationName":"updateParkingData"}

When I ran your python code, it produced this:

{"query": "mutation updateParkingData {updateParkingData(input: {ParkingLotName: test, availableSpaces: 1, capacity: 1}){ParkingLotName, availableSpaces, capacity}}"}

Notice how the value for ParkingLotName is quoted in the working version, and not quoted in the second. Modifying json_string's declaration should produce a valid query:

json_string = "{{ParkingLotName: \"{}\", availableSpaces: {}, capacity: {}}}".format(parkingLotName, availableSpaces, capacity)
answered 5 years ago
0

Hello, thank you for the reply.

I changed the json_string line to "{{ParkingLotName: \"{}\", availableSpaces: \"{}\", capacity: \"{}\"}}".format(parkingLotName, availableSpaces, capacity) because availableSpaces and capacity are Strings as well, but when running the program, CloudWatch tells me that my mutations are failing with status code 400, malformed request, and shows me my Graphql query:

GraphQL Query: mutation updateParkingData {updateParkingData(input: {ParkingLotName: ""AquaLot"", availableSpaces: ""98"", capacity: ""29%""}){ParkingLotName, availableSpaces, capacity}}, Operation: null, Variables:
{}

How do I add the operation and the variables?

answered 5 years ago
0

Interesting, it looks like the library is already escaping the strings for you across the wire and so the additional quotes in our request caused the 400 error.

You can add variables and operationName like so:

data = {"query": mutation_string, "variables": variables, "operationName": "updateParkingData"}

Do you have any CloudWatch logs / RequestIds from other attempts so I can help you further?

answered 5 years ago
0

I'm just going to share an entire log, sorry if it's too much information!

990b6daf-56b7-44ec-b4e7-125fde581d90 Begin Request
990b6daf-56b7-44ec-b4e7-125fde581d90 GraphQL Query: mutation updateParkingData {updateParkingData(input: {ParkingLotName: "AquaLot", availableSpaces: "100", capacity: "28%"}){ParkingLotName, availableSpaces, capacity}}, Operation: null, Variables:
{}
990b6daf-56b7-44ec-b4e7-125fde581d90 Begin Execution - Type Name: Mutation and Field Name: updateParkingData
{
    "logType": "RequestMapping",
    "path": [
        "updateParkingData"
    ],
    "fieldName": "updateParkingData",
    "resolverArn": "arn:aws:appsync:us-east-1:386770239021:apis/***/types/Mutation/fields/updateParkingData",
    "requestId": "990b6daf-56b7-44ec-b4e7-125fde581d90",
    "context": {
        "arguments": {
            "input": {
                "ParkingLotName": "AquaLot",
                "availableSpaces": "100",
                "capacity": "28%"
            }
        },
        "stash": {},
        "outErrors": []
    },
    "fieldInError": false,
    "errors": [],
    "parentType": "Mutation",
    "graphQLAPIId": "****",
    "transformedTemplate": "\n{\n    \"version\": \"2017-02-28\",\n    \"payload\": {\n        \"body\": \"${context.arguments.body}\",\n        \"from\": \"${context.identity.username}\",\n        \"to\":  \"${context.arguments.to}\",\n        \"sentAt\": \"2019-08-29T17:42:55.526Z\"\n    }\n}"
}
{
    "logType": "ResponseMapping",
    "path": [
        "updateParkingData"
    ],
    "fieldName": "updateParkingData",
    "resolverArn": "arn:aws:appsync:us-east-1:386770239021:apis/***/types/Mutation/fields/updateParkingData",
    "requestId": "990b6daf-56b7-44ec-b4e7-125fde581d90",
    "context": {
        "arguments": {
            "input": {
                "ParkingLotName": "AquaLot",
                "availableSpaces": "100",
                "capacity": "28%"
            }
        },
        "result": {
            "body": "${context.arguments.body}",
            "from": "${context.identity.username}",
            "to": "${context.arguments.to}",
            "sentAt": "2019-08-29T17:42:55.526Z"
        },
        "stash": {},
        "outErrors": []
    },
    "fieldInError": false,
    "errors": [],
    "parentType": "Mutation",
    "graphQLAPIId": "****",
    "transformedTemplate": "{body=${context.arguments.body}, from=${context.identity.username}, to=${context.arguments.to}, sentAt=2019-08-29T17:42:55.526Z}"
}
990b6daf-56b7-44ec-b4e7-125fde581d90 End Field Execution
{
    "duration": 1879758,
    "logType": "ExecutionSummary",
    "requestId": "990b6daf-56b7-44ec-b4e7-125fde581d90",
    "startTime": "2019-08-29T17:42:55.525Z",
    "endTime": "2019-08-29T17:42:55.527Z",
    "parsing": {
        "startOffset": 55905,
        "duration": 43170
    },
    "version": 1,
    "validation": {
        "startOffset": 149788,
        "duration": 85183
    },
    "graphQLAPIId": "***"
}
990b6daf-56b7-44ec-b4e7-125fde581d90 Begin Tracing
{
    "duration": 1375547,
    "logType": "Tracing",
    "path": [
        "updateParkingData"
    ],
    "fieldName": "updateParkingData",
    "startOffset": 205055,
    "resolverArn": "arn:aws:appsync:us-east-1:386770239021:apis/***/types/Mutation/fields/updateParkingData",
    "requestId": "990b6daf-56b7-44ec-b4e7-125fde581d90",
    "parentType": "Mutation",
    "returnType": "ParkingData",
    "graphQLAPIId": "***"
}
{
    "duration": 25154,
    "logType": "Tracing",
    "path": [
        "updateParkingData",
        "ParkingLotName"
    ],
    "fieldName": "ParkingLotName",
    "startOffset": 1614683,
    "requestId": "990b6daf-56b7-44ec-b4e7-125fde581d90",
    "parentType": "ParkingData",
    "returnType": "String!",
    "graphQLAPIId": "****"
}
{
    "duration": 14051,
    "logType": "Tracing",
    "path": [
        "updateParkingData",
        "availableSpaces"
    ],
    "fieldName": "availableSpaces",
    "startOffset": 1730132,
    "requestId": "990b6daf-56b7-44ec-b4e7-125fde581d90",
    "parentType": "ParkingData",
    "returnType": "String",
    "graphQLAPIId": "***"
}
{
    "duration": 4516,
    "logType": "Tracing",
    "path": [
        "updateParkingData",
        "capacity"
    ],
    "fieldName": "capacity",
    "startOffset": 1748887,
    "requestId": "990b6daf-56b7-44ec-b4e7-125fde581d90",
    "parentType": "ParkingData",
    "returnType": "String",
    "graphQLAPIId": "***"
}
990b6daf-56b7-44ec-b4e7-125fde581d90 End Tracing
{
    "logType": "RequestSummary",
    "requestId": "990b6daf-56b7-44ec-b4e7-125fde581d90",
    "graphQLAPIId": "***",
    "statusCode": 200,
    "latency": 31000000
}
990b6daf-56b7-44ec-b4e7-125fde581d90 Request Headers: {Content-Type=[application/json; charset=UTF-8]}
990b6daf-56b7-44ec-b4e7-125fde581d90 Response Headers: {content-length=185, cloudfront-viewer-country=US, x-forwarded-proto=https, x-forwarded-port=443, x-forwarded-for=3.80.6.153, 70.132.32.136, via=1.1 3b8e0d5ce152e011bcc1dba2235e26b8.cloudfront.net (CloudFront), accept=*/*, cloudfront-is-smarttv-viewer=false, x-amzn-trace-id=Root=1-5d680e9f-391f37cccbb29ab0f0868678, cloudfront-is-desktop-viewer=true, cloudfront-is-tablet-viewer=false, x-api-key=*******, host=*****.appsync-api.us-east-1.amazonaws.com, content-type=application/graphql, cloudfront-forwarded-proto=https, x-amz-cf-id=zYbrFdWv4rLDAZwzccjk3Sy_-vzH5ZwBoTI7zUoM_PZuHRSyVxHyHQ==, accept-encoding=gzip, deflate, user-agent=python-requests/2.7.0 CPython/3.7.3 Linux/4.14.123-95.109.amzn2.x86_64, cloudfront-is-mobile-viewer=false}
990b6daf-56b7-44ec-b4e7-125fde581d90 End Request
answered 5 years ago
0

It looks like your response mapping template is referencing some different fields than what you expect on your types. Are you intending to map from, to, body, sentAt? I think you need to bind to your ${context.args.input} and return that.

answered 5 years ago
0

That did it! My mutations are showing up in my app now! Thank you so much; I've been stuck on this problem for days!

answered 5 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions