How to Create Custom Scalar Type in GraphQL
To create a custom scalar type in GraphQL, define a new
GraphQLScalarType with serialization, parsing, and validation logic. Then, add it to your schema and use it like built-in scalars.Syntax
Creating a custom scalar involves defining a GraphQLScalarType object with three main functions:
- serialize: Converts internal data to a format sent to the client.
- parseValue: Converts client input to internal data.
- parseLiteral: Parses hardcoded query values.
After defining, you add the scalar to your schema and use it in type definitions.
javascript
const { GraphQLScalarType, Kind } = require('graphql'); const CustomScalar = new GraphQLScalarType({ name: 'CustomScalar', description: 'Description of custom scalar', serialize(value) { // Convert internal value to client }, parseValue(value) { // Convert client input to internal }, parseLiteral(ast) { // Parse hardcoded query value if (ast.kind === Kind.STRING) { return ast.value; } return null; } });
Example
This example creates a Date scalar that handles JavaScript Date objects as ISO strings in GraphQL.
javascript
const { GraphQLScalarType, Kind } = require('graphql'); const DateScalar = new GraphQLScalarType({ name: 'Date', description: 'Custom scalar for dates in ISO format', serialize(value) { if (!(value instanceof Date)) { throw new TypeError('Value is not an instance of Date'); } return value.toISOString(); // send ISO string to client }, parseValue(value) { const date = new Date(value); if (isNaN(date.getTime())) { throw new TypeError('Value is not a valid Date'); } return date; // convert client input to Date }, parseLiteral(ast) { if (ast.kind === Kind.STRING) { const date = new Date(ast.value); if (isNaN(date.getTime())) { throw new TypeError('Value is not a valid Date'); } return date; // convert hardcoded query value } return null; } }); // Usage in schema definition const typeDefs = ` scalar Date type Event { id: ID! name: String! date: Date! } `; // Resolver map const resolvers = { Date: DateScalar, Query: { event: () => ({ id: '1', name: 'Party', date: new Date() }) } };
Output
{
"data": {
"event": {
"id": "1",
"name": "Party",
"date": "2024-06-01T12:00:00.000Z"
}
}
}
Common Pitfalls
- Not implementing all three functions (
serialize,parseValue,parseLiteral) causes errors. - Failing to validate input data can lead to invalid values in your API.
- Returning wrong types in
serializeorparseValuebreaks the schema. - Forgetting to add the scalar to your schema and resolvers means it won't work.
javascript
/* Wrong: Missing parseLiteral */ const BadScalar = new GraphQLScalarType({ name: 'BadScalar', serialize(value) { return value; }, parseValue(value) { return value; } }); /* Right: Implement all three */ const GoodScalar = new GraphQLScalarType({ name: 'GoodScalar', serialize(value) { return value; }, parseValue(value) { return value; }, parseLiteral(ast) { return ast.value; } });
Quick Reference
Remember these key points when creating custom scalars:
- serialize: Output format for clients.
- parseValue: Input from variables.
- parseLiteral: Input from inline queries.
- Always validate data in each function.
- Register scalar in schema and resolvers.
Key Takeaways
Define a GraphQLScalarType with serialize, parseValue, and parseLiteral functions.
Validate and convert data properly in each function to avoid errors.
Add the custom scalar to your schema and resolvers to use it.
Always implement all three functions to handle client and query inputs.
Use custom scalars to handle special data types like dates or JSON.