Labs ICT
Pro Login

Custom Scalars

Custom Scalars

GraphQL comes with five built-in scalar types (String, Int, Float, Boolean, ID), but sometimes you need more specific types. Custom scalars let you define your own primitive types.

Common use cases include DateTime, Email, URL, JSON, and other specialized types.

Using Custom Scalars

First, you declare the custom scalar in your schema. Then you need to implement serialization and parsing logic.

const { GraphQLScalarType } = require('graphql');

const typeDefs = `
  scalar DateTime
  scalar Email
  scalar JSON

  type Post {
    id: ID!
    title: String!
    content: String!
    createdAt: DateTime!
    updatedAt: DateTime!
  }

  type User {
    id: ID!
    name: String!
    email: Email!
    metadata: JSON
  }
`;

The schema declares DateTime, Email, and JSON as scalar types. Now we need to implement how they work.

Implementing DateTime

Here's how to implement a DateTime scalar that handles ISO date strings:

const DateTimeScalar = new GraphQLScalarType({
  name: 'DateTime',
  description: 'ISO 8601 date-time string',
  serialize(value) {
    // Convert from internal value to JSON
    if (value instanceof Date) {
      return value.toISOString();
    }
    throw new Error('DateTime must be a Date object');
  },
  parseValue(value) {
    // Convert from JSON to internal value
    const date = new Date(value);
    if (isNaN(date.getTime())) {
      throw new Error('Invalid DateTime format');
    }
    return date;
  },
  parseLiteral(ast) {
    // Convert from query string to internal value
    if (ast.kind === 'StringValue') {
      const date = new Date(ast.value);
      if (isNaN(date.getTime())) {
        throw new Error('Invalid DateTime format');
      }
      return date;
    }
    throw new Error('DateTime must be a string');
  },
});

The scalar has three methods: serialize (server to client), parseValue (client to server), and parseLiteral (query string to server).

Using graphql-scalars Library

You don't always need to implement scalars from scratch. The graphql-scalars library provides many common types:

const {
  DateTimeResolver,
  EmailAddressResolver,
  URLResolver,
  JSONResolver,
} = require('graphql-scalars');

const resolvers = {
  DateTime: DateTimeResolver,
  Email: EmailAddressResolver,
  URL: URLResolver,
  JSON: JSONResolver,
  // ... other resolvers
};

The library handles all the serialization and parsing logic for you. Just import and use.

When to Use Custom Scalars

Use custom scalars when you need:

Date/Time: ISO 8601 formatted dates (DateTime scalar)

Email: Validated email addresses (EmailAddress scalar)

URL: Validated URLs (URL scalar)

JSON: Flexible JSON data (JSON scalar)

PositiveInt: Numbers greater than zero

type Mutation {
  createUser(input: CreateUserInput!): User!
}

input CreateUserInput {
  name: String!
  email: EmailAddress!
  birthday: DateTime
  website: URL
  preferences: JSON
}

Custom scalars add validation and clarity to your API. Clients know exactly what format to expect.