aws-appsync-community icon indicating copy to clipboard operation
aws-appsync-community copied to clipboard

Numbers from DynamoDB results can't be converted to string

Open sashee opened this issue 11 months ago • 0 comments

I have items coming from DynamoDB. When a field is a number then when I use something like ctx.result.num + "" the result is "null".

For example, I have a table with this item:

  • id: {S: "1"}
  • num: {N: "100"}

In the resolver, I get this item:

export function request(ctx) {
	return {
		version : "2018-05-29",
		operation : "GetItem",
		key : {
			id : {S: "1"}
		},
		consistentRead : true
	}
}

In the response handler, I try to convert the field to a string:

export function response(ctx) {
	return {
		res: ctx.result.num,
		normal: ctx.result.num + "",
		fixed: ctx.result.num + 0 + "",
	}
}

The result I get:

{"res":100,"normal":"null","fixed":"100"}"

Both the typeof ctx.result.num and typeof (ctx.result.num + 0) yields number, but there is clearly a difference between them.

A full reproduction example:

provider "aws" {
}
resource "random_id" "id" {
  byte_length = 8
}
resource "aws_iam_role" "appsync" {
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Effect": "Allow"
    }
  ]
}
EOF
}
data "aws_iam_policy_document" "appsync" {
  statement {
    actions = [
      "dynamodb:GetItem",
    ]
    resources = [
      aws_dynamodb_table.test.arn,
    ]
  }
}
resource "aws_iam_role_policy" "appsync" {
  role   = aws_iam_role.appsync.id
  policy = data.aws_iam_policy_document.appsync.json
}
resource "aws_appsync_graphql_api" "appsync" {
  name                = "test"
  schema              = <<EOF
type Query {
	test: AWSJSON
}
schema {
	query: Query
}
EOF
  authentication_type = "AWS_IAM"
}
resource "aws_appsync_datasource" "ddb_test" {
  api_id           = aws_appsync_graphql_api.appsync.id
  name             = "ddb_test"
  service_role_arn = aws_iam_role.appsync.arn
  type             = "AMAZON_DYNAMODB"
  dynamodb_config {
    table_name = aws_dynamodb_table.test.name
  }
}

resource "aws_dynamodb_table" "test" {
  name         = "test-${random_id.id.hex}"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "id"
  attribute {
    name = "id"
    type = "S"
  }
}

resource "aws_dynamodb_table_item" "item" {
  table_name = aws_dynamodb_table.test.name
  hash_key   = aws_dynamodb_table.test.hash_key
  item = <<ITEM
{
  "id": {"S": "1"},
	"num": {"N": "100"}
}
ITEM
}

resource "aws_appsync_resolver" "test" {
  api_id = aws_appsync_graphql_api.appsync.id
  type              = "Query"
  field             = "test"
  runtime {
    name            = "APPSYNC_JS"
    runtime_version = "1.0.0"
  }
  code = <<EOF
export function request(ctx) {
	return {};
}
export function response(ctx) {
	return ctx.result;
}
EOF
  kind = "PIPELINE"
  pipeline_config {
    functions = [
      aws_appsync_function.test.function_id,
    ]
  }
}
resource "aws_appsync_function" "test" {
  api_id            = aws_appsync_graphql_api.appsync.id
  data_source       = aws_appsync_datasource.ddb_test.name
	name = "test"
  runtime {
    name            = "APPSYNC_JS"
    runtime_version = "1.0.0"
  }
  code = <<EOF
import {util} from "@aws-appsync/utils";
export function request(ctx) {
	return {
		version : "2018-05-29",
		operation : "GetItem",
		key : {
			id : {S: "1"}
		},
		consistentRead : true
	}
}
export function response(ctx) {
	if (ctx.error) {
		return util.error(ctx.error.message, ctx.error.type);
	}
	return {
		res: ctx.result.num,
		normal: ctx.result.num + "",
		fixed: ctx.result.num + 0 + "",
	}
}
EOF
}
  • deploy with Terraform (terraform init and terraform apply)
  • send query:
query MyQuery {
  test
}
  • see the result:
{
  "data": {
    "test": "{\"res\":100,\"normal\":\"null\",\"fixed\":\"100\"}"
  }
}

sashee avatar Jul 25 '23 09:07 sashee