aws-amplify / amplify-category-api

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of GraphQL and REST based backends for your amplify project.
https://docs.amplify.aws/
Apache License 2.0
89 stars 79 forks source link

Adding validation to fields in graphql api schema #447

Open rayhaanq opened 6 years ago

rayhaanq commented 6 years ago

Which Category is your question related to? Amplify GraphQL API

Is it possible to add validation to fields in the schema file? So min/max length, min/max value etc? If I had a field on a Person type and wanted to limit their name field to 250 characters, is that possible using the schema file only? Otherwise how can this be done?

mikeparisstuff commented 6 years ago

We don't package any transformers that allow you to do this out of the box but have discussed use cases like this in the past. If you want to do this purely using the schema.graphql today, you can write your own transformer that will augment the generated resolver template code. To make this work you will also need to write your own light-weight CLI that loads and runs the transformer. There are docs on this here https://aws-amplify.github.io/docs/js/graphql#writing-custom-transformers.

The way to implement this in AppSync is to write resolver code that validates inputs during mutations. For example, if you wanted to validate that the "name" is a max of 250 characters then you would add a snippet like this to createPerson and updatePerson resolvers:

## mutation.create/updatePerson.request.vtl **
#if( $ctx.args.input.name.length() > 250 )
    $util.error("Value for input field `CreatePersonInput.name` cannot exceed 250 characters.")
#end

If you provided a name longer than 250 characters this would cause the mutation to fail before saving the object to DynamoDB. This is how your custom transformer would work too, but you would be generating the above snippet in your transformer instead of writing it by hand.

mikeparisstuff commented 6 years ago

What directives would you like access to? Over the long term, we can work on building a few transformers that tackle common issues but it would be helpful to hear more about the use cases you want to be solved.

For example, I would suspect these two would be useful:

@regex

directive @regex(expression: String!) on FIELD_DEFINITION

Usage

type Post {
  id: ID!
  title: String @regex(expression: ".*graphql.*")
}

@length

directive @length(min: Int, max: Int) on FIELD_DEFINITION

Usage

type Post {
  id: ID!
  title: String @length(min: 10, max: 255)
}

There are a lot of possibilities so let me know what you think and we will prioritize based on demand.

rayhaanq commented 6 years ago

@mikeparisstuff thanks for the code snippet. I'll take a look at this. As for the possible directives. I guess what you mentioned sounds reasonable with the addition of maybe:

there's also a few common simplified regex checks I guess. @startsWIth, @endsWith, @contains

also for the length implementation, should max be optional somehow? Maybe we want the value to be at least 10.

mikeparisstuff commented 5 years ago

@rayhaanq Thanks for those suggestions. I will take a note of all of these and will try to write up a more formal design that covers a subset of useful directives and publish it so that we can get more feedback on these features.

This is also another good use case for supporting custom transformers that would allow you to define your own directives that could be run as part of the Amplify CLI. For example, you could write a transformer on your local machine and then import it such that it is loaded by the amplify CLI:

"transformers": [
  "path/to/local/transformer.js"
]

Would you be interested in such functionality? This would provide another safety hatch for advanced behavior that is not supported OOTB by the transform.

sassoo commented 5 years ago

I would be interested for sure. I was looking for something like a @readonly directive which would cause the field to be excluded from the generated Inputs but available for "reading". I'd imagine a @writeonly field might be something we'd want as well. Maybe something like @toUpper @toLower, etc. It would be great to be able to create these on our own even if not available in core amplify-cli.

darkxeno commented 5 years ago

Do we have any update about those new directives? This is a very interesting matter if we want to build an complete application while writing the minimum of serveless code

paulsson commented 5 years ago

This would be amazing! Hoping for news on availability soon... maybe re:Invent?!

mikigraf commented 4 years ago

This would be great and would really make writing complex models a breeze! Is there anything planned for above mentioned directives?

andreialecu commented 4 years ago

I would be interested for sure. I was looking for something like a @readonly directive which would cause the field to be excluded from the generated Inputs but available for "reading". I'd imagine a @writeonly field might be something we'd want as well. Maybe something like @toupper @tolower, etc. It would be great to be able to create these on our own even if not available in core amplify-cli.

I think the @readonly usage is covered by: https://www.npmjs.com/package/graphql-auto-transformer by @hirochachacha

And there's @tolower: https://www.npmjs.com/package/graphql-lowercase-transformer by @hisham

Hopefully someone can step in and create the directives mentioned by @mikeparisstuff above.

hirochachacha commented 4 years ago

I've made https://github.com/hirochachacha/graphql-assert-transformer

type Post @model {
  id: ID!
  title: String @assert(condition: """.length() > 3 && .matches("t.*")""")
  text: String @assert(condition: ".length() > 10")
  episode: Int @assert(condition: ". % 2 == 0")
}
dtelaroli commented 4 years ago

It would be great something like this to uniq validation or any other necessity:

@custom("lambda-${env}")
igorkosta commented 4 years ago

Any updates on the custom field validations?

kaustavghosh06 commented 4 years ago

Fro custom field level validations, I would highly recommend looking at writing custom transformer directive plugins based on our docs here - https://docs.amplify.aws/cli/plugins/authoring#custom-graphql-transformers

Found a similar 3rd party custom directive plugin here for field level validations/operations - https://www.npmjs.com/package/graphql-default-value-transformer and the code for which is here https://github.com/trek10inc/graphql-default-value-transformer

kaustavghosh06 commented 4 years ago

Also, as @andreialecu mentioned there are some more 3rd party custom directives which you could leverage:

@readonly usage is covered by: https://www.npmjs.com/package/graphql-auto-transformer by @hirochachacha @tolower: https://www.npmjs.com/package/graphql-lowercase-transformer by @hisham

If you'd like something really specific which can't be built with a custom directive and which all our customers can leverage as a default, I would recommend opening up an RFC in our repo and we can discuss it for including it as a part of our code offering.

yaquawa commented 3 years ago

any updates on this??

cfbo commented 3 years ago

Any update on this? Is there any plan to integrate something like https://github.com/hirochachacha/graphql-assert-transformer within amplify? I suppose validation is quite a common use case for every one. I understand it is possible to write custom resolvers, but having the chance to declare it in the schema.graphql like shown in graphql-assert-transformer would be a great advantage I reckon.

413n commented 3 years ago

+1

BatteryAcid commented 2 years ago

If I'm understanding correctly, there's no simple way to have a lambda function perform validation as part of an update action on a model, right?

I was hoping a directive like @function on a model would allow me to check the data that's about to be applied in the update and reject it if it fails my validation - currently this is not the case, but I would like to see something similar to this. I feel like custom validation is essential but I'm not finding a straightforward way to accomplish it, any insight would be helpful. Thanks!

josefaidt commented 2 years ago

relevant in regards to constraints aws-amplify/amplify-category-api#286

BatteryAcid commented 2 years ago

If I'm understanding correctly, there's no simple way to have a lambda function perform validation as part of an update action on a model, right? ...

Maybe I missed this before or my use case was different, but I found that I can add a custom mutation to my schema that points to a Lambda resolver to perform the operation. Here I was able to perform the necessary validation before the update was complete.
I followed this guide: https://www.theclouddeveloper.io/use-lambda-resolvers-in-your-graph-ql-api-with-aws-amplify

I guess this is what you do when you need something outside of the generated CRUD operations.

SaddemAmine commented 2 years ago

It has been 4 years. Nothing yet? 🥴

craig-at-metashield-io commented 1 year ago

it's been 5 years and still nothing from the aws team. 😢

in the absence of any official movement, i've created a set of input validation directives for strings (String) and numbers (Int and Float). however, it is currently blocked by #2077

~once~ if this gets resolved, then i will publish these to npm.

and if we do get there, i will expand the validators to date/time (AWSDate, AWSTime, AWSDateTime), etc

we can only hope.

craig-at-metashield-io commented 12 months ago

i have it working now - i will release to npm shortly.