Skip to content

Instantly share code, notes, and snippets.

@whoisYeshua
Created December 13, 2025 06:44
Show Gist options
  • Select an option

  • Save whoisYeshua/36ed2734435a8b43b6d56b30cbbe550b to your computer and use it in GitHub Desktop.

Select an option

Save whoisYeshua/36ed2734435a8b43b6d56b30cbbe550b to your computer and use it in GitHub Desktop.
GraphQL custom scalars
{
"schema": "https://apollo-whoisyeshua-test.onrender.com",
"documents": "**/*.{graphql,gql}"
}
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { ApolloServer } from '@apollo/server'
import { startStandaloneServer } from '@apollo/server/standalone'
import { addMocksToSchema } from '@graphql-tools/mock'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { bigintScalar } from './scalars/bigintScalar.js'
import { dateScalar } from './scalars/dateScalar.js'
const typeDefsPath = resolve('./schema.gql')
const typeDefs = readFileSync(typeDefsPath).toString('utf-8')
const resolvers = {
Bigint: bigintScalar,
Date: dateScalar,
Query: {
test: () => 'test2',
age: () => Number.MAX_SAFE_INTEGER - 1,
date: () => new Date(),
},
}
const mocks = {
Int: () => 6,
Float: () => 22.1,
String: () => 'Hello',
Date: () => new Date('2011', '11', '11'),
Bigint: () => 3_000_000_000,
}
const server = new ApolloServer({
schema: addMocksToSchema({
schema: makeExecutableSchema({ typeDefs, resolvers }),
preserveResolvers: true,
mocks,
}),
introspection: true,
})
const { url } = await startStandaloneServer(server, { listen: { port: 4000 } })
console.log(`🚀 Server listening at: ${url}`)
{
"name": "apollo-test",
"type": "module",
"scripts": {
"build": "echo \"No build step currently\"",
"start": "node index.js",
"dev": "nodemon index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@apollo/server": "^4.7.3",
"graphql": "^16.6.0",
"nodemon": "^2.0.22"
},
"devDependencies": {
"@graphql-tools/mock": "^9.0.0",
"@graphql-tools/schema": "^10.0.0"
},
"engines": {
"node": "16.20.0"
}
}
import { GraphQLScalarType, Kind, GraphQLError } from 'graphql'
const MAX_INT = Number.MAX_SAFE_INTEGER
const MIN_INT = Number.MIN_SAFE_INTEGER
const coerceBigint = value => {
if (value === '') {
throw new GraphQLError(
'Bigint не может представлять не 53-битное целочисленное значение: (пустая строка)'
)
}
const num = Number(value)
if (num > MAX_INT || num < MIN_INT) {
throw new GraphQLError(
`Bigint не может представлять не 53-битное целочисленное значение: ${String(value)}`
)
}
const int = Math.floor(num)
if (int !== num) {
throw new GraphQLError(`Bigint не может представлять нецелое значение: ${String(value)}`)
}
return int
}
export const bigintScalar = new GraphQLScalarType({
name: 'Bigint',
description:
'Скалярный тип `Bigint` представляет нефракционные целые числовые значения. Bigint может представлять значения между -(2^53) + 1 и 2^53 - 1.',
serialize: coerceBigint,
parseValue: coerceBigint,
parseLiteral(ast) {
if (ast.kind === Kind.INT) {
const num = parseInt(ast.value, 10)
if (num <= MAX_INT && num >= MIN_INT) {
return num
}
}
return null
},
})
import { GraphQLScalarType, Kind, GraphQLError } from 'graphql'
export const dateScalar = new GraphQLScalarType({
name: 'Date',
description: 'Пользовательский скалярный тип даты',
serialize(value) {
if (value instanceof Date) {
return value.getTime() // Convert outgoing Date to integer for JSON
}
throw new GraphQLError('Сериализатор GraphQL Date Scalar ожидает объект `Date`')
},
parseValue(value) {
if (typeof value === 'number') {
return new Date(value) // Convert incoming integer to Date
}
throw new GraphQLError('Парсер GraphQL Date Scalar ожидает получить `number`')
},
parseLiteral(ast) {
if (ast.kind === Kind.INT) {
// Convert hard-coded AST string to integer and then to Date
return new Date(parseInt(ast.value, 10))
}
// Invalid hard-coded value (not an integer)
return null
},
})
scalar Date
scalar Bigint
type Query {
"Получение списка континентов"
continents(pagination: Pagination): [Continent!]
"Получение континента по коду"
continent(code: String): Continent
"Получение списка стран"
countries(pagination: Pagination): [Country!]
"Получение страны по коду"
country(code: String): Country
test: String # test query
age: Bigint!
date: Date
}
"Пагинация по списку"
input Pagination {
"Смещение"
offset: Int
"Лимит"
limit: Int
}
"Континент"
type Continent {
"Код континента"
code: String!
"Название континента"
name: String
"Страны континента"
countries(pagination: Pagination): [Country]
}
"Страна"
type Country {
"Код страны"
code: String!
"Название страны"
name: String
"Название страны на родном языке"
native: String
"Телефонный код страны"
phone: String
"Континент, к которому принадлежит страна"
continent: Continent
"Штаты/области страны"
states(pagination: Pagination): [State!]
}
"Штат"
type State {
"Код штата/области"
code: String!
"Название штата/области"
name: String
"Страна, к которой принадлежит штат/область"
country: Country
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment