Scalars (ScalarTypeDefinition) are indivisible atomic data types in GraphQL that act as leaf nodes in the service. For the client, a valid Select Set must reach a leaf node, that is, a scalar node.
The GraphQL specification provides five types of scalars:
- Int: a 32-bit signed integer. The engine will throw an exception if the precision exceeds the range
- Float: a signed, double-precision floating point number that is thrown by the engine outside the precision range
- String: Indicates a character string
UTF-8
Character sequence - Boolean: the Boolean value
- ID: unique identifier of the resource
1. ID properties
The five types mentioned above are similar to their counterparts in other languages, and I believe readers are already familiar with them. The only type worth discussing is the ID type.
- On the performance
ID
A type is just a value in string format. The engine supports string parsing as well as convertingInt
Parsed values are converted to string types; - Semantically. “”
ID
“Type should be used to uniquely identify a resource object. That is, no matter how many times you query with the same ID, the result should be the same object. This is useful for caching. - The engine does not limit the uniqueness of resolved values, and it is legal for query results to contain multiple nodes with the same ID value.
Let’s look at some examples to impress:
[
// A string of characters
{id: '1'},
// int, which the engine will convert to a string
{id: 1},
/ / float type
// Invalid value, the engine does not support float conversion
// A 'TypeError' error will be thrown
{id: 1.2},
// Repeat the first step above
// The engine does not enforce the uniqueness of the 'ID' value
{id: '1'}]Copy the code
2. Customize scalar types
In addition to the scalars defined by the specification, scalars within a business category can be defined on demand. The syntax is very simple:
scalar Datetime
Copy the code
Note that this is only a semantic category definition, and you also need to define serialization and deserialization functions:
new GraphQLScalarType({
name: "Datetime".description: "Date-time scalar type".// Serialize the function
serialize(value) {
return value.toString();
},
// Parse the function
parseValue(value) {
if (typeof value === "string") {
return new Date(value);
}
throw new Error("Parameter type error");
},
// Parse the function
parseLiteral(ast) {
if (ast.kind === Kind.STRING) {
return new Date(ast.value);
}
throw new Error("Parameter type error"); }});Copy the code
Let’s look at each configuration one by one:
name
: Field name, please keep withschemaThe scalar type names specified indescription
: type description, useful in some diagnostic toolsserialize
: serialization function that converts the result to a numeric type suitable for HTTP transportparseValue
: parsing function, used to pass the clientvariablesThe value passed as a parameter is of type DateparseLiteral
: is also a parsing function that passes the clientLiteral parameterResolves to Date type
The parseValue and parseLiteral functions in the configuration are similar in function. Both parseValue and parseLiteral are used to parse client parameters.
Query (before: Datetime){users(before: $before) {id name}} variables {before: Query {users(before: "1991-02-19") {id name}}Copy the code
A few final caveats:
- If the type is determined it will not act
InputType
Can be omittedparseValue
,parseLiteral
. parseValue
The received isvariables
The corresponding value in the object; whileparseLiteral
The receiver is the engine fromquery
The AST node parsed from the statement. The AST node content looks like:
{// literal type "kind": "StringValue", // literal value" value": "1991-02-19", / / specify literal is [BlockStringValue] (https://facebook.github.io/graphql/June2018/#BlockStringValue ()) type "block" : False, // token position "loc": {"start": 18, "end": 30}}Copy the code
3. Return the scalar of the object
Scalar types also support the return of structured objects, as long as the engine has a serialize function that complies with the rules, anything is possible. We can write a scalar like this:
// Address object type, but this is a scalar
new GraphQLScalarType({
name: "Address".description: "Scalar of object type",
serialize(value) {
// value is the object type
// value = {city: 'shenzhen ', province:' guangdong ', country: 'China'}
returnvalue; }});Copy the code
Note, however, that scalar types are indivisible and cannot be passed in a subset of queries:
{users {id name # Address bornOrigin}}Copy the code
Return result:
{
"data": {
"users": [{"id": "1"."name": "foo"."bornOrigin": {
"city": "Shenzhen"."province": "Guangdong province"."country": "China"}}]}}Copy the code
The full code is here. While legitimate, using a scalar type to return an undetachable object violates the important principle of loading on demand and is not worth advocating unless a better solution is found. For example, when we need to deal with highly dynamic information structures and we want to transmit information in a structured and predictable way, we have to adopt this approach. Take the log as an example. For a relatively large-scale system, log formats are diverse. If you need to enumerate them one by one and convert them into GraphQL’S SDL one by one, the development and maintenance costs are very high.
conclusion
Scalars are atomic types in GraphQL that typically serve as leaf nodes for queries. The GraphQL specification provides five scalar types, of which ID is the most special, for uniquely identifying a resource instance. In addition to standard scalars, new scalars can also be defined on demand, as described above.