首页 > 解决方案 > Optional relation on MySQL RDB with foreign keys using AWS Appsync

问题描述

I've got an Aurora Serverless RDB set up with a couple tables with a foreign key. I've got some basic VTL resolvers working at translating the GraphQL queries to SQL, but I'm running into trouble when one of the referenced objects only shows up on some items.

This is my (simplified) schema:

type TodoItem {
    id: ID!
    title: String!
    done: Boolean!
    context: TaskContext
}

type TaskContext {
    id: ID!
    name: String!
}

input CreateTodoItemInput {
    title: String!
    done: Boolean!
    contextId: ID
}

input CreateContextInput {
    name: String!
}

type Mutation {
    createTodoItem(input: CreateTodoItemInput!): TodoItem
    createContext(input: CreateContextInput!): TaskContext
}

type Query {
    listTodoItems: [TodoItem!]!
}

So a task has an optional context associated with it. For listTodoItems this is my resolver request template:

{
    "version": "2018-05-29",
    "statements": [
        "SELECT i.id, i.title, i.done, c.id contextId, c.name contextName FROM todo_items i LEFT JOIN contexts c ON i.contextId = c.id"
    ]
}

And this is my response. I look at the contextName and contextId fields and create the Context item for it.

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $utils.error($ctx.error.message, $ctx.error.type)
#end

#set($rdsResult = $utils.rds.toJsonObject($ctx.result)[0])
#foreach($rdsResultItem in $rdsResult)
  #if($rdsResultItem.contextId) {
    #set($rdsResultItem.context = {
      "id": $rdsResultItem.contextId,
      "name": $rdsResultItem.contextName
    })
  #end
#end

$utils.toJson($rdsResult)

But when I run the query, I get this result:

Unable to convert 
   {

[
    {
        "contextName": "Work",
        "contextId": "6daa656b-5007-49e2-a584-d1399c5e7479",
        "id": "11879932-a51a-49d2-b9aa-672b8b30871a",
        "title": "Sample item 3",
        "done": false,
        "context": {
            "id": "6daa656b-5007-49e2-a584-d1399c5e7479",
            "name": "Work"
        }
    }, {
        "id": "021531f0-1846-49a7-8f11-67d5e56d7d99",
        "title": "Sample item",
        "done": true
    }, {
        "id": "864387dd-1e3b-49f2-8cdc-1ea8e3d8b901",
        "title": "Sample item",
        "done": false
    }
]

to class java.lang.Object.

I cleaned up some of the JSON escaping to make it more readable. If I set the "context" object on all of them (with null values for id and name), it works but it complains about a schema violation. None of the guides for writing resolvers to MySQL RDB covered how to do field relations. I also tried auto-generating the templates/schema from amplify api add-graphql-datasource but it spit out a simplistic model that did not take into account the foreign key relation.

Can anyone tell me how to set up the resolvers correctly here?

标签: mysqlaws-appsyncvtl

解决方案


You need to remove the { after the if statement in VTL. That segment of your mapping template should look like

#foreach($rdsResultItem in $rdsResult)
  #if($rdsResultItem.contextId)
    #set($rdsResultItem.context = {
      "id": $rdsResultItem.contextId,
      "name": $rdsResultItem.contextName
    })
  #end
#end

The signature of an if statement in VTL looks like:

#if( $condition )
  Conditionally-evaluated lines
#end

For a VTL reference, check out https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-programming-guide.html#conditional-checks


推荐阅读