GraphQL Java - Scalars

GraphQL of Scalar

The Scalar (atom type)

In GraphQL type system, the type of tree leaf node becomes Scalar. Once access to the Scalar types of data, you can not further access type hierarchy under which the type basis. Scalar type means that the value of this type can not be subdivided.

In GraphQL specification, which requires that all implementations must have the Scalar Type:

  • Type String (GraphQLString): UTF-8 character encoding sequence
  • Boolean type (GraphQLBoolean): true or false
  • Int type (GraphQLInt): 32-bit signed type
  • Float type (GraphQLFloat): single precision floating point type
  • Type ID (GraphQLID): a unique identifier type (can be serialized into String). However, poor readability of the data type ID.

GraphQL - Java supplement adds several additional types as follows:

  • Long type (GraphQLLong): Based on scalar type of java.lang.Long
  • Short type (GraphQLShort): based on the scalar type java.lang.Short
  • Type Byte (GraphQLByte): based on the scalar type java.lang.Byte
  • BigDecimal type (GraphQLBigDecimal): based on the scalar type java.math.BigDecimal
  • BigInteger type (GraphQLBigInteger): based on the scalar type java.math.BigInteger

graphql.Scalars class contains examples of all existing scalar singleton type.

Scalar write custom type

You can customize the Scalar type. In this implementation, the need for data type mapping mechanism to themselves at runtime.

Suppose we have a scalar type of email, it will use the email address as output and output.

EMAIL creation of a scalar types are as follows:

        public static final GraphQLScalarType EMAIL = new GraphQLScalarType("email", "A custom scalar that handles emails", new Coercing() {
            @Override
            public Object serialize(Object dataFetcherResult) {
                return serializeEmail(dataFetcherResult);
            }

            @Override
            public Object parseValue(Object input) {
                return parseEmailFromVariable(input);
            }

            @Override
            public Object parseLiteral(Object input) {
                return parseEmailFromAstLiteral(input);
            }
        });

Data mapping

Since the definition of scalar sight, the core part of the work is to achieve data mapping. The main need to achieve the following three methods:

  • parseValue: receiving a variable input, and then converted to an object in the Java runtime.
  • parseLiteral: receiving a constant AST (graphql.language.Value type) as input, into an object in the Java runtime.
  • serialize: receiving a Java object, it is represented as scalar converting the output form.

Custom scalar, it is necessary to implement the conversion of two input (parseValue / parseLiteral) and a conversion of the output (serialize).

For example, for the implementation of the following statement:

    mutation Contact($mainContact: Email!) {
      makeContact(mainContactEmail: $mainContact, backupContactEmail: "[email protected]") {
        id
        mainContactEmail
      }
    }

Custom Email scalar type will have the following call:

  • parseValue method is called, will convert $ mailContact variable runtime data in Java.
  • parseLiterial method is called, the AST's graphql.language.StringValue ([email protected]) is converted into runtime data in Java.
  • serialise method is called, the operation mainContactEmail when said conversion of the output form graphQL.

Input and output validation

Whether scalar definition may validate the input or output data is valid. For example: email email is a valid data type.

graphql.schema.Coercing the following provisions:

  • serialise only allowed to throw graphql.schema.CoercingSerializeException types of exceptions. It means that value can not be serialized value into the appropriate data form. At the same time, we must ensure that other types of runtime exception will not be thrown from serialise method. Further, the return value must be non-null.
  • parseValue only allowed to throw graphql.schema.CoercingSerializeException types of exceptions. It means that value can not be resolved to the appropriate value of the input data format. At the same time, we must ensure that other types of runtime exception will not be thrown from parseValue method. Further, the return value must be non-null.
  • parseLiteral only allowed to throw graphql.schema.CoercingSerializeException types of exceptions. It means that AST constant values ​​that can not be resolved to the appropriate input data format. At the same time, we must ensure that other types of runtime exception will not be thrown from parseLiteral method. Further, the return value must be non-null.

Some views dependent runtime exception to achieve authentication, and outputs them in a desired form graphql error. But that is not the case. When you customize Scalar, you must adhere to standards Coercing methods in order to make GraphQL - Java to run properly.

Examples

Here is a new complex class Scalar Email achieved.

    public static class EmailScalar {

        public static final GraphQLScalarType EMAIL = new GraphQLScalarType("email", "A custom scalar that handles emails", new Coercing() {
            @Override
            public Object serialize(Object dataFetcherResult) {
                return serializeEmail(dataFetcherResult);
            }

            @Override
            public Object parseValue(Object input) {
                return parseEmailFromVariable(input);
            }

            @Override
            public Object parseLiteral(Object input) {
                return parseEmailFromAstLiteral(input);
            }
        });


        private static boolean looksLikeAnEmailAddress(String possibleEmailValue) {
            // ps.  I am not trying to replicate RFC-3696 clearly
            return Pattern.matches("[A-Za-z0-9]@[.*]", possibleEmailValue);
        }

        private static Object serializeEmail(Object dataFetcherResult) {
            String possibleEmailValue = String.valueOf(dataFetcherResult);
            if (looksLikeAnEmailAddress(possibleEmailValue)) {
                return possibleEmailValue;
            } else {
                throw new CoercingSerializeException("Unable to serialize " + possibleEmailValue + " as an email address");
            }
        }

        private static Object parseEmailFromVariable(Object input) {
            if (input instanceof String) {
                String possibleEmailValue = input.toString();
                if (looksLikeAnEmailAddress(possibleEmailValue)) {
                    return possibleEmailValue;
                }
            }
            throw new CoercingParseValueException("Unable to parse variable value " + input + " as an email address");
        }

        private static Object parseEmailFromAstLiteral(Object input) {
            if (input instanceof StringValue) {
                String possibleEmailValue = ((StringValue) input).getValue();
                if (looksLikeAnEmailAddress(possibleEmailValue)) {
                    return possibleEmailValue;
                }
            }
            throw new CoercingParseLiteralException(
                    "Value is not any email address : '" + String.valueOf(input) + "'"
            );
        }
    }

Guess you like

Origin www.cnblogs.com/pku-liuqiang/p/11528040.html