Amplify-cli: @key vs. @connection

Created on 13 Jun 2019  路  12Comments  路  Source: aws-amplify/amplify-cli

Which Category is your question related to?
API

What AWS Services are you utilizing?
AppSync

Provide additional details e.g. code snippets
When should I use @connection as opposed to @key? It seems to me I can do many-to-many or one-to-many relationship using both directives. Is @key meant to replace @connection? Or would there be a specific use case where @connection might be more useful? I tried looking up documentation and issues and @mikeparisstuff said in https://github.com/aws-amplify/amplify-cli/issues/1406#issuecomment-494533788:

The @connection directive will then go through some sort of deprecation and re-introduction process.

Does that mean we should ditch @connection now that @key is introduced?

graphql-transformer pending-response question

Most helpful comment

jeez this @key stuff is strange especially when the @connection does all the work for you. Just need a quick solution for sorting values.

All 12 comments

Hey @calspre, the @connection directive will not be going away, but we are considering a new directive that enables many of the same use cases but is built upon @key. The @connection directive abstracts away the underlying index configuration and indexes cannot be changed in significant ways after being created. This abstraction led to confusion and errors when trying to change a @connection's fields or arguments. Using @key provides more hands on control of the table and will be the recommended way of configuring indexes moving forward and we have updated the documentation to recommend a pattern where you introduce new indexes before removing old ones to avoid update issues related to GSIs.

Thanks @mikeparisstuff for the response.

Using @key provides more hands on control of the table and will be the recommended way of configuring indexes moving forward [...]

Is it safe to assume that @connection will be there for backward compatibility but @key will be a more flexible, recommended way for index configuration (since you are considering a new directive that's built on @key)?

[...] and we have updated the documentation to recommend a pattern where you introduce new indexes before removing old ones to avoid update issues related to GSIs.

Are you referring to this section?

If @key is a recommended way, is there a way to delete existing @connection and somehow migrate to @key directive? I am a little scared to touch @connection due to the known CloudFormation issues and if there's a certain procedure to migrate like the link above, I am happy to follow.

@calspre Yes @connection will remain for backwards compatible reasons and the intention is to provide a new mechanism the achieves the same goal but that allows you to change the @connection after the fact (even though you still will not be able to change index structures after the fact and should follow the create a new index before deleting an old index process).

It is possible to replace a @connection with a @key but should be done carefully. Here is one method you can use to move towards @key.

Given this schema:

type Post @model {
  id: ID!
  title: String
  comments: [Comment] @connection(name: "PostComments")
}

type Comment @model {
  id: ID!
  content: String
  post: Post @connection(name: "PostComments")
}

If you look at build/stacks/Comment.json, you will see the CommentTable with the following GSI definition:

"GlobalSecondaryIndexes": [
    {
        "IndexName": "gsi-PostComments",
        "KeySchema": [
            {
                "AttributeName": "commentPostId",
                "KeyType": "HASH"
            }
        ],
        "Projection": {
            "ProjectionType": "ALL"
        },
        "ProvisionedThroughput": {
            ...
        }
    }
]

To can replace the @connection with the @key by adding:

type Post @model {
  id: ID!
  title: String
  comments: [Comment]
}

type Comment @model @key(name: "gsi-PostComments", fields: ["commentPostId"], queryField: "commentsByPost") {
  id: ID!
  content: String
  post: Post
}

You need to make sure the names match and the order of the attributes included in the key schema match that of the "fields" argument.

Note: DynamoDB has the restriction that you cannot change a GSI & cannot remove and create a GSI in the same CFN update.

One disclaimer is that until the new directive you will lose the Post.comments & Comment.post resolvers but will gain a Query.commentsByPost resolver that achieves a similar result. If you want to make sure that the migration is doing what you think, you can compare the values of build/stacks/Comment.json before and after the change.

Thanks @mikeparisstuff! That sounds reasonable. I will give it a try.

@calspre Closing this issue for now, please feel free to comment on this thread if you still have any queries around this.

@mikeparisstuff Is there any documentation to use a key instead of connection from scratch? I tried the example above and got the error that the commentPostId field didn't exist.

@mikeparisstuff Is there any documentation to use a key instead of connection from scratch? I tried the example above and got the error that the commentPostId field didn't exist.

Yes just read the docs it clearly shows how you should create the keys you're using in your @key transformer in your graphQL schema. I haven't tested this yet but in the case of migrating the fact that your table already has that field setup through @connection is probably why you can omit it. Again I haven't tested this so I don't know if you can actually omit it or was this just a shorthand demo.

@amirmishani The docs does not say anything about using @key instead of @connection, it only shows how to use @key and query it with a single table

When will this new @key be made available?

jeez this @key stuff is strange especially when the @connection does all the work for you. Just need a quick solution for sorting values.

@connection lets you reverse query the parent field, @key would require you to write your own resolvers to achieve the same function. If I am not mistaken there isn't any additional cost involved with that resolver right? Then isn't @connection a really good feature to maintain. If you choose not to use reverse mapping ever, you can go with implementing only @key with name,fields. Or will you be adding reverse query as an option under @key? Then there would be no use for @connection

@mikeparisstuff I changed all @connection to @key due to this post but now I noticed that my non-scalar are not automatically added to the filters.

For example:

type Ad @model @key(name: "adsByUser", fields: ["userID"]) {
  id: ID
  userID: String!
  publishedAt: AWSDateTime!
  price: Float!
  location: Location!
}

type Location {
  district: Int!
  county: Int
  parish: Int
}

The filters are automatically added for publishedAt or price but not for location. Any idea what I'm doing wrong?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adriatikgashi picture adriatikgashi  路  3Comments

kangks picture kangks  路  3Comments

jexh picture jexh  路  3Comments

ffxsam picture ffxsam  路  3Comments

onlybakam picture onlybakam  路  3Comments