为 AWS AppSync 中的 SQL 查询字符串化 JSON 对象
Stringify JSON object for SQL query in AWS AppSync
问题:如何在我的 Appsync velocity 模板中为 SQL 语句字符串化 JSON 对象?
说明:我有一个 Aurora RDS table,它有一个数据类型为 JSON 的列。 AppSync API 已连接到 RDS。
我的 GraphQL 模式看起来像
input CreateServiceCatalogItemInput {
serviceName: String!
serviceConfig: ServiceConfigInput!
}
type Mutation {
createServiceCatalogItem(input: CreateServiceCatalogItemInput!): ServiceCatalogItem
}
type Query {
getAllServiceCatalogItem: [ServiceCatalogItem]
}
type ServiceCatalogItem {
serviceId: ID!
serviceName: String!
serviceConfig: ServiceConfig!
}
type ServiceConfig {
connectionType: String
capacity: Int
}
input ServiceConfigInput {
connectionType: String
capacity: Int
}
schema {
query: Query
mutation: Mutation
}
我的 createServiceCatalogItem 突变解析器看起来像
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.toString($ctx.args.input.serviceConfig)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
这会引发错误:
在 class com.amazonaws.deepdish.transform.util.TransformUtils 中调用方法 'toString' 抛出异常 java.lang.IllegalArgumentException:... 处的参数数量错误
如果我这样做:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.toJson($ctx.args.input.serviceConfig)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
这会引发错误:
无法解析 JSON 文档:'意外字符('c'(代码 99)):需要用逗号分隔数组 entries\n at .. .
如果我这样做:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$ctx.args.input.serviceConfig') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
然后我得到了有意义的错误:
RDSHttp:{"message":"错误:类型 json\n 的输入语法无效详细信息:令牌 \"connectionType\" 无效。\n 位置:222\n其中:JSON 数据,第 1 行:{connectionType..."}
然而,当我在我的解析器中硬编码 JSON 时,它起作用了:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '{\"connectionType\":\"ftth\",\"capacity\":1}') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
那么如何将 {connectionType=ftth, capacity=1} 转换为 {"connectionType":"ftth", "capacity":1}?我做错了什么或者我错过了什么?任何帮助将不胜感激。
解决方案 1:
感谢@cyberwombat 我能够解决这个问题。如果有人需要,我将其发布为参考。
我的 serviceConfig
对象不是固定的,可能会随时间变化,所以我修改了我的解析器以使其更通用,它看起来像这样:
#set($serviceConfigMap = {})
#foreach($key in $ctx.args.input.serviceConfig.keySet())
$util.qr($serviceConfigMap.put("$key", $ctx.args.input.serviceConfig.get($key)))
#end
#set($serviceConfigMap = $util.toJson($serviceConfigMap))
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.escapeJavaScript($serviceConfigMap)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
旧解:
这是我之前解决这个问题的方法。
我将解析器转换为管道,并在 NodeJS 中创建了一个简单的 Lambda 函数来对 JSON 对象进行字符串化。这就是我的 lambda 函数的样子:
exports.handler = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify(event.input.serviceConfig).replace(/\"/g, '\\"'),
};
callback(null, response)
};
这就是 serviceConfig 现在的样子,也是我想要的样子:
{\"connectionType\":\"ftth\",\"maxUploadCapacity\":1}"
我现在可以在我的解析器中的 SQL 语句中轻松使用它。
您可以像这样构建一个 JSON 变量:
#set($json = $util.toJson({
"connectionType": "$ctx.args.input.serviceConfig.connectionType",
"capacity": $ctx.args.input.serviceConfig.capacity
}))
并在您的查询中插入:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.escapeJavaScript($json)' RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
由于所有引号和转义,上面的内容有点具有挑战性,但我认为使用 escapeJavaScript
可以解决问题。
或直接:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '{\"connectionType\":\"$ctx.args.input.serviceConfig.connectionType\",\"capacity\": $ctx.args.input.serviceConfig.capacity}') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
问题:如何在我的 Appsync velocity 模板中为 SQL 语句字符串化 JSON 对象?
说明:我有一个 Aurora RDS table,它有一个数据类型为 JSON 的列。 AppSync API 已连接到 RDS。 我的 GraphQL 模式看起来像
input CreateServiceCatalogItemInput {
serviceName: String!
serviceConfig: ServiceConfigInput!
}
type Mutation {
createServiceCatalogItem(input: CreateServiceCatalogItemInput!): ServiceCatalogItem
}
type Query {
getAllServiceCatalogItem: [ServiceCatalogItem]
}
type ServiceCatalogItem {
serviceId: ID!
serviceName: String!
serviceConfig: ServiceConfig!
}
type ServiceConfig {
connectionType: String
capacity: Int
}
input ServiceConfigInput {
connectionType: String
capacity: Int
}
schema {
query: Query
mutation: Mutation
}
我的 createServiceCatalogItem 突变解析器看起来像
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.toString($ctx.args.input.serviceConfig)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
这会引发错误:
在 class com.amazonaws.deepdish.transform.util.TransformUtils 中调用方法 'toString' 抛出异常 java.lang.IllegalArgumentException:... 处的参数数量错误
如果我这样做:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.toJson($ctx.args.input.serviceConfig)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
这会引发错误:
无法解析 JSON 文档:'意外字符('c'(代码 99)):需要用逗号分隔数组 entries\n at .. .
如果我这样做:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$ctx.args.input.serviceConfig') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
然后我得到了有意义的错误:
RDSHttp:{"message":"错误:类型 json\n 的输入语法无效详细信息:令牌 \"connectionType\" 无效。\n 位置:222\n其中:JSON 数据,第 1 行:{connectionType..."}
然而,当我在我的解析器中硬编码 JSON 时,它起作用了:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '{\"connectionType\":\"ftth\",\"capacity\":1}') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
那么如何将 {connectionType=ftth, capacity=1} 转换为 {"connectionType":"ftth", "capacity":1}?我做错了什么或者我错过了什么?任何帮助将不胜感激。
解决方案 1:
感谢@cyberwombat 我能够解决这个问题。如果有人需要,我将其发布为参考。
我的 serviceConfig
对象不是固定的,可能会随时间变化,所以我修改了我的解析器以使其更通用,它看起来像这样:
#set($serviceConfigMap = {})
#foreach($key in $ctx.args.input.serviceConfig.keySet())
$util.qr($serviceConfigMap.put("$key", $ctx.args.input.serviceConfig.get($key)))
#end
#set($serviceConfigMap = $util.toJson($serviceConfigMap))
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.escapeJavaScript($serviceConfigMap)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
旧解:
这是我之前解决这个问题的方法。
我将解析器转换为管道,并在 NodeJS 中创建了一个简单的 Lambda 函数来对 JSON 对象进行字符串化。这就是我的 lambda 函数的样子:
exports.handler = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify(event.input.serviceConfig).replace(/\"/g, '\\"'),
};
callback(null, response)
};
这就是 serviceConfig 现在的样子,也是我想要的样子:
{\"connectionType\":\"ftth\",\"maxUploadCapacity\":1}"
我现在可以在我的解析器中的 SQL 语句中轻松使用它。
您可以像这样构建一个 JSON 变量:
#set($json = $util.toJson({
"connectionType": "$ctx.args.input.serviceConfig.connectionType",
"capacity": $ctx.args.input.serviceConfig.capacity
}))
并在您的查询中插入:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.escapeJavaScript($json)' RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}
由于所有引号和转义,上面的内容有点具有挑战性,但我认为使用 escapeJavaScript
可以解决问题。
或直接:
{
"version": "2018-05-29",
"statements": [
"INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '{\"connectionType\":\"$ctx.args.input.serviceConfig.connectionType\",\"capacity\": $ctx.args.input.serviceConfig.capacity}') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
]
}