Custom scalar creation utilities for advanced use cases. These utilities allow developers to create custom GraphQL scalar types with regex-based validation for domain-specific requirements.
Base class for creating custom GraphQL scalar types with regular expression validation.
/**
* Base class for creating custom GraphQL scalar types with regex validation
* Extends GraphQLScalarType with regex-based validation logic
*/
class RegularExpression extends GraphQLScalarType {
constructor(name: string, regex: RegExp, options?: RegularExpressionOptions);
}Parameters:
name: The name of the custom scalar typeregex: Regular expression pattern for validationoptions: Optional configuration objectConfiguration interface for customizing RegularExpression behavior.
interface RegularExpressionOptions {
/** Custom error message function */
errorMessage?: RegularExpressionErrorMessageFn;
/** Description for the scalar type */
description?: string;
/** Whether to only accept string values */
stringOnly?: boolean;
}Function type for generating custom error messages.
/**
* Function type for generating custom validation error messages
* @param r - The regular expression that failed validation
* @param v - The value that failed validation
* @returns Custom error message string
*/
type RegularExpressionErrorMessageFn = (r: RegExp, v: any) => string;import { RegularExpression } from "graphql-scalars";
// Create a custom scalar for product codes
const GraphQLProductCode = new RegularExpression(
"ProductCode",
/^[A-Z]{2}-[0-9]{4}-[A-Z]{2}$/,
{
description: "Product code in format XX-0000-XX",
errorMessage: (regex, value) =>
`Product code must match format XX-0000-XX, got: ${value}`,
stringOnly: true
}
);
// Create a custom scalar for license plates
const GraphQLLicensePlate = new RegularExpression(
"LicensePlate",
/^[A-Z0-9]{1,8}$/,
{
description: "Vehicle license plate (1-8 alphanumeric characters)",
stringOnly: true
}
);
// Create a custom scalar for hex colors (alternative to built-in)
const GraphQLCustomHexColor = new RegularExpression(
"CustomHexColor",
/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,
{
description: "Hexadecimal color code (#RGB or #RRGGBB)",
errorMessage: (regex, value) =>
`Invalid hex color format: ${value}. Expected #RGB or #RRGGBB`,
stringOnly: true
}
);import { GraphQLObjectType, GraphQLString, GraphQLSchema } from "graphql";
// Define schema using custom scalars
const ProductType = new GraphQLObjectType({
name: "Product",
fields: {
id: { type: GraphQLProductCode },
name: { type: GraphQLString },
color: { type: GraphQLCustomHexColor },
},
});
const VehicleType = new GraphQLObjectType({
name: "Vehicle",
fields: {
licensePlate: { type: GraphQLLicensePlate },
make: { type: GraphQLString },
model: { type: GraphQLString },
},
});
// Schema with type definitions
const typeDefs = `
scalar ProductCode
scalar LicensePlate
scalar CustomHexColor
type Product {
id: ProductCode!
name: String!
color: CustomHexColor
}
type Vehicle {
licensePlate: LicensePlate!
make: String!
model: String!
}
`;
// Resolvers map
const resolvers = {
ProductCode: GraphQLProductCode,
LicensePlate: GraphQLLicensePlate,
CustomHexColor: GraphQLCustomHexColor,
};// Social Security Number (US format)
const GraphQLSSN = new RegularExpression(
"SSN",
/^\d{3}-\d{2}-\d{4}$/,
{
description: "US Social Security Number (XXX-XX-XXXX)",
errorMessage: (regex, value) =>
`SSN must be in format XXX-XX-XXXX, got: ${value}`,
stringOnly: true
}
);
// Credit Card Number (basic format validation)
const GraphQLCreditCard = new RegularExpression(
"CreditCard",
/^\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}$/,
{
description: "Credit card number (16 digits with optional spaces or dashes)",
errorMessage: (regex, value) =>
`Invalid credit card format: ${value}`,
stringOnly: true
}
);
// Stock Symbol
const GraphQLStockSymbol = new RegularExpression(
"StockSymbol",
/^[A-Z]{1,5}$/,
{
description: "Stock trading symbol (1-5 uppercase letters)",
errorMessage: (regex, value) =>
`Stock symbol must be 1-5 uppercase letters, got: ${value}`,
stringOnly: true
}
);
// Semantic Version (custom implementation)
const GraphQLCustomSemVer = new RegularExpression(
"CustomSemVer",
/^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9\-\.]+))?(?:\+([a-zA-Z0-9\-\.]+))?$/,
{
description: "Semantic version (MAJOR.MINOR.PATCH)",
errorMessage: (regex, value) =>
`Invalid semantic version format: ${value}. Expected MAJOR.MINOR.PATCH`,
stringOnly: true
}
);When stringOnly: true, the scalar will only accept string literals in GraphQL queries:
// With stringOnly: true
const GraphQLStrictCode = new RegularExpression(
"StrictCode",
/^[A-Z]{3}$/,
{ stringOnly: true }
);
// Valid GraphQL usage:
// mutation { createItem(code: "ABC") }
// Invalid GraphQL usage (will throw error):
// mutation { createItem(code: 123) }Provide meaningful error messages for better developer experience:
const GraphQLCustomFormat = new RegularExpression(
"CustomFormat",
/^[A-Z]{2}-\d{4}$/,
{
errorMessage: (regex, value) => {
if (typeof value !== 'string') {
return `Expected string value, got ${typeof value}: ${value}`;
}
if (value.length !== 7) {
return `Expected 7 characters (XX-0000), got ${value.length}: ${value}`;
}
return `Invalid format. Expected XX-0000 pattern, got: ${value}`;
}
}
);# Query using custom scalars
query GetProduct($productId: ProductCode!) {
product(id: $productId) {
id
name
color
}
}
# Mutation with validation
mutation CreateVehicle($input: VehicleInput!) {
createVehicle(input: $input) {
licensePlate
make
model
}
}Variables:
{
"productId": "AB-1234-CD",
"input": {
"licensePlate": "ABC123",
"make": "Toyota",
"model": "Camry"
}
}// Valid values for custom scalars
const validData = {
productCode: "AB-1234-CD", // Matches XX-0000-XX pattern
licensePlate: "ABC123", // 1-8 alphanumeric characters
hexColor: "#FF5733", // Valid hex color
ssn: "123-45-6789", // Valid SSN format
stockSymbol: "AAPL" // 1-5 uppercase letters
};
// Invalid values (will fail validation)
const invalidData = {
productCode: "AB-12345-CD", // Too many digits
licensePlate: "ABC@123", // Special character not allowed
hexColor: "#GG5733", // Invalid hex characters
ssn: "123456789", // Missing dashes
stockSymbol: "apple" // Lowercase not allowed
};RegularExpression is ideal for:
Consider using specific built-in scalars when available, as they often provide better validation and error messages than custom regex-based solutions.