# Scalars

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

-   Type alias declaration

```ts
/**
 * A description of my custom scalar.
 * @gqlScalar <optional name of the scalar, if different from type name>
 */
export 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.

```ts
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`](https://spec.graphql.org/draft/#sec--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' support for [annotating your schema with directives](./directive-annotations.md) lets you add this directive to your custom scalars:

```tsx
/**
 * @gqlScalar
 * @gqlAnnotate specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
 */
export type UUID = string;
```

_Generated GraphQL schema:_

```graphql
scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
```

## Serialization and Parsing of Custom Scalars

When defining a custom scalar, Grats will require that when constructing your schema you provide a configuration object for the scalar which can optionally define how to serialize and parse values of that type.

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

scalars.ts

```ts
/** @gqlScalar Date */
export type GqlDate = Date;
```

Grats' generated `getSchema` would require a config object where you could supply `serialize/parseValue/parseLiteral` transform for this type. If `Date` were serialized as a Unix timestamp, you could do the following:

server.ts

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

const config: SchemaConfig = {
  scalars: {
    Date: {
      serialize(value): number {
        if (!(value instanceof Date)) {
          throw new Error("Date.serialize: value is not a Date object");
        }
        return value.getTime();
      },
      parseValue(value): Date {
        if (typeof value !== "number") {
          throw new Error("Date.parseValue: value is not a number");
        }
        return new Date(value);
      },
      parseLiteral(ast): Date {
        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));
      },
    },
  },
};

const schema = getSchema(config);

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