AWS-Amplify API module: how to make GraphQL fields unique?
Asked Answered
S

2

15

AWS-Amplify provides a couple of directives to build an GraphQL-API. But I haven't found out how to ensure uniqueness for fields.

I want to do something like in GraphCool:

type Tag @model @searchable {
  id: ID!
  label: String! @isUnique
}

This is an AWS-Amplify specific question. It's not about how to do this with generic GraphQL. It's very specifically about how to do this with AWS-Amplify's API module. (https://aws-amplify.github.io/docs/js/api)

Stokes answered 4/1, 2019 at 10:52 Comment(0)
S
7

Hey thanks for the question. This is not yet possible by default using the amplify-cli but you could do this yourself using pipeline resolvers and an extra index on your DynamoDB table. The steps to do this are as follows:

  1. Create a GSI on the table where the label is the HASH KEY.
  2. Create a pipeline resolver on the Mutation.createTag field in your schema. You can turn off the auto-generated Mutation.createTag mutation by changing your @model definition to @model(mutations: { update: "updateTag", delete: "deleteTag" }).
  3. Create a function named LookupLabel that issues a Query against the new GSI where the label = $ctx.args.input.label. If this returns a value, throw an error with $util.error("Label is not unique"). If it returns no values then continue.
  4. Create a function named CreateTag that issues a PutItem against the Tag table.
  5. Add those two functions in order to your pipeline resolver.

You can read more about pipeline resolvers here https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html.

As of writing amplify does not yet support custom & pipeline resolvers but you can read more about the feature here https://github.com/aws-amplify/amplify-cli/issues/574 as it will be supported in the future. For now you can add the resolver manually in the AWS AppSync console or via your own CloudFormation template that targets the id of the API created by Amplify. It would also be helpful if you create an issue here (https://github.com/aws-amplify/amplify-cli/issues) and tag this as a feature request because it would be possible to automate this with an @unique directive but this would need to be planned.

Thanks

Steamboat answered 4/1, 2019 at 20:7 Comment(7)
Thank you for the detailed elaboration! I believe that Amplify and the AWS services are very powerful, but the developer experience is quiet awful. Every module has some complicated configuration and/or handling to it, and I've never felt so much pain developing. I really like the concept and the idea behind it, but this was the last straw. I will remove Amplify and all the modules (except hosting) and take a more "traditional" approach. I'm not getting things done with this.Stokes
Sorry to hear that you have had a hard time getting started. We are constantly working on improving developer experience and I would like to hear more about the major pain points you found and if these new designs would address them. If you are open to it I would like to schedule some time for us to talk so we can hear the full extent of your feedback in order to help improve the service. Please let me know if you are interested. Thanks.Steamboat
Yes of course. Like I said, I like the idea and would love to see it evolve into something much more easy and intuitive to use. I have listed most of my points @ jaypad.io/ok11k7rhp4ujuj54Stokes
Thank you for the more detailed notes these are very helpful. I will take some time to look over and think on these comments and may reach out with more questions. Thank you for your feedback.Steamboat
A video of this would be great too. 🙏Unbelief
It's more than a year and no progress?Lalonde
I believe the process of adding custom resolvers has been simplified now with the GraphQL Transformer, but a clearer explanation of how to add one to enforce a unique field would be really nice.Lockwood
F
1

Update: now you can use @primarykey and @index annotations: https://docs.amplify.aws/cli/migration/transformer-migration/#what-is-changing

basic:

profile @model {
name
email @primaryKey  - has to be unique
other
}

so if you needed something like:

profile @model {
name
email: String! @hasOne
other
}

email @model {
email: String! @primaryKey
}

if you are on an older version see below I will eventually be testing this out to see if this works but you might be able to do something like rename the id to a string! so...

type Tag @model @key["id"] {
id: String!
}

or:

type Customer @model @key(fields: ["email"]) {
email: String!
username: String
}

this second one is taken directly from the docs: https://docs.amplify.aws/cli/graphql-transformer/key#designing-data-models-using-key
The docs were updated recently so hopefully they are easier for everyone to understand.

If you need a more advanced workflow with allot of keys, and stuff like that then you just have to separate things out and make more types for example:

 type Customer @model { 
  id: String! 
  email: Email! @hasOne 
  username: String 
} 

type email @model @key(fields: ["email"]) { 
email: String! 
}  
Fracture answered 22/1, 2021 at 18:12 Comment(2)
That only works for the primary key. You can't add additional unique indices this way.Sixfooter
it depends on your schema and what you are building. i think maybe you could think about it like this -> ``` type Customer @model { id: String! email: Email! @hasOne username: String } type email @model @key(fields: ["email"]) { email: String! } ``` please read docs.amplify.aws/cli/usage/mock/… for more infoFracture

© 2022 - 2024 — McMap. All rights reserved.