Skip to main content

Scalars

GraphQL custom scalars can be defined by placing a @gqlScalar docblock directly before a:

  • Type alias declaration
/**
* A description of my custom scalar.
* @gqlScalar <optional name of the scalar, if different from type name>
*/
type MyCustomString = string;

Built-In Scalars

note

For built-in GraphQL scalars that don't have a corresponding TypeScript type, Grats ships with type aliases you can import. You may be prompted to use one of these by Grats if you try to use number in a position from which Grats needs to infer a GraphQL type.

import { Float, Int, ID } from "grats";

/** @gqlType */
class Math {
id: ID;
/** @gqlField */
round(args: { float: Float }): Int {
return Math.round(args.float);
}
}

@specifiedBy Directive

The GraphQL specification defines the @specifiedBy directive which can be added to custom scalar definitions. The directive provides a "scalar specification URL for specifying the behavior of custom scalar types.". Grats lets you add this directive to your custom scalars by adding a @specifiedBy docblock tag to the type alias declaration followed by the URL of the specification.

/**
* @gqlScalar
* @specifiedBy https://tools.ietf.org/html/rfc4122
*/
type UUID = string;
Playground

Serialization and Parsing of Custom Scalars

Grats does not (yet) support a first-class way to define serialization and parsing logic for custom scalars. However, you can do this manually by modifying the schema after it is generated.

For example if you had a Date type in your schema:

scalars.ts
/** @gqlScalar Date */
export type GqlDate = Date;

To define a custom serialize/parseValue/parseLiteral transform for this type, which serialized the data as a Unix timestamp, you could do the following:

server.ts
import { getSchema } from "./schema"; // Generated by Grats
import { GqlDate } from "./scalars";

const schema = getSchema();

const date = schema.getType("Date") as GraphQLScalarType<GqlDate, number>;

date.serialize = (value) => {
if (!(value instanceof Date)) {
throw new Error("Date.serialize: value is not a Date object");
}
return value.getTime();
};
date.parseValue = (value) => {
if (typeof value !== "number") {
throw new Error("Date.parseValue: value is not a number");
}
return new Date(value);
};
date.parseLiteral = (ast) => {
if (!(ast.kind === "IntValue" || ast.kind === "StringValue")) {
throw new Error(
"Date.parseLiteral: ast.kind is not IntValue or StringValue",
);
}
return new Date(Number(ast.value));
};

// ... Continue on, using the schema to create a GraphQL server