-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Input Validation #6
Comments
After further code reading/debugging, it looks like the current implementation is buggy when nested inputs are used. I'll do a pull request during the fix those issues. |
any luck on this? I am having same issue and my Input type fields/objects doesn't get validated. |
I have found sort of a workaround, such that I can at least have input validation :) maybe this can help some people. It misuses the fact that you can create your own scalar types. class ValidateFieldException(message: String) : RuntimeException(message)
interface ValidateFieldHandler {
val name: String
@Throws(ValidateFieldException::class)
fun validate(value: Any)
}
class ValidateCoercing<I, O>(
private val original: Coercing<I, O>,
private val validateHandler: ValidateFieldHandler
) : Coercing<I, O> by original {
override fun parseValue(input: Any): I {
validate(input)
return original.parseValue(input)
}
override fun parseLiteral(input: Any): I {
validate(input)
return original.parseLiteral(input)
}
private fun validate(input: Any) {
try {
validateHandler.validate(input)
} catch (ex: ValidateFieldException) {
throw CoercingParseValueException.newCoercingParseValueException()
.message(ex.message)
.errorClassification(ErrorType.ValidationError)
.cause(ex)
.build()
}
}
}
class ValidateDirective(
private val validateFieldHandlerCreator: ((String) -> GraphQLArgument?) -> ValidateFieldHandler
) : SchemaDirectiveWiring {
override fun onInputObjectField(environment: SchemaDirectiveWiringEnvironment<GraphQLInputObjectField>): GraphQLInputObjectField =
environment.element.wrapWithValidateFieldHandler(environment, validateFieldHandlerCreator(environment.directive::getArgument))
/**
* Create a new GraphQLType to add validation on a specific type. Like verifying it is a String we add validation rules too, like min-length, max-length.
*/
private fun GraphQLInputObjectField.wrapWithValidateFieldHandler(
environment: SchemaDirectiveWiringEnvironment<GraphQLInputObjectField>,
handler: ValidateFieldHandler
): GraphQLInputObjectField = transform { builder ->
// Generate unique ID for the custom type
val uniqueFieldId = environment.nodeParentTree.path.reversed().joinToString(separator = "")
// Handle GraphQLNonNull wrapped object
val currentType = type
val unwrappedType = if (currentType is GraphQLNonNull) currentType.wrappedType else currentType
// Create a new type that has the ValidateCoercing handler and wrap it around the current one
val newType = when (unwrappedType) {
is GraphQLScalarType -> {
GraphQLScalarType
.newScalar(unwrappedType)
.name("$uniqueFieldId${handler.name}${unwrappedType.name}Validated")
.coercing(ValidateCoercing(unwrappedType.coercing, handler))
.build()
}
else -> currentType
}
// Set the new type to the current type
builder.type(if (currentType is GraphQLNonNull) GraphQLNonNull.nonNull(newType) else newType)
}
}
class AlphaNumericFieldValidator : ValidateFieldHandler {
object Creator {
fun create(arg: (String) -> GraphQLArgument?): ValidateFieldHandler = AlphaNumericFieldValidator()
}
private val regex = "^[A-Za-z0-9]*$".toRegex()
override val name: String = "AlphaNumeric"
override fun validate(value: Any) {
if (value is String && !value.matches(regex)) {
throw ValidateFieldException("Only alpha-numeric allowed, got: `$value`")
}
}
} And on my directive("AlphaNumeric", ValidateDirective(AlphaNumericFieldValidator.Creator::create)) |
Two stock Instrumentations (MaxQueryDepthInstrumentation and MaxQueryComplexityInstrumentation) call graphql.analysis.QueryTraverser$Builder.build() which throws graphql.schema.CoercingParseValueException if the nested input does not conform to the definition. This causes an unexpected error and results in a 400 http response which is undesirable. These instrumentations should probably catch those errors and add them to the list. There should also be validation of nested input fields in variables before graphql.execution.instrumentation.SimpleInstrumentation.beginValidation() is called. Stack trace: |
Any updates on this? |
Hello,
Thank you for your work on this extended validation. This is very helpful.
I am using graphql-java-kickstart with a very basic schema, and noticed that input used as arguments of a mutation would not be validated unless in an array with its own rule.
Example:
Am I missing something? Is it the intended behavior or a restriction of graphql-java-tools (if so, it should be documented)?
The text was updated successfully, but these errors were encountered: