GraphQL 默认支持五种标量类型:Int,Float,String,Boolean 和 ID,可以满足大部分的使用场景,但有时候需要一些特殊的属性类型,此时我们就可以使用自定义标量类型来实现。下面看一下怎么通过自定义标量类型来实现一个 DateTime 类型。
mkdir myapp
cd myapp
npm init (一路回车)
npm install @apollo/server graphql
创建 schema.graphql 文件,内容如下:
scalar DateTime
type User {
id: ID!
name: String!
email: String!
registerDateTime: DateTime!
}
type Query {
users: [User],
user(registerDateTime: DateTime!): User,
}
type Mutation {
createUser(name: String!, email: String!, registerDateTime: DateTime!) : User!
}
schema {
query: Query
mutation: Mutation
}
schema 文件主要包括:
创建 resolvers.js 文件,内容如下:
const { GraphQLScalarType, Kind } = require('graphql');
const user1 = { id: 1, name: 'user1', email: 'user1@gmail.com', registerDateTime: new Date('2000-01-01T10:10:10.000Z') };
const user2 = { id: 2, name: 'user2', email: 'user2@gmail.com', registerDateTime: new Date('2000-01-01T10:10:10.000Z') };
const user3 = { id: 3, name: 'user3', email: 'user3@gmail.com', registerDateTime: new Date('2000-01-01T10:10:10.000Z') };
const users = [user1, user2, user3];
const datetimeScalar = new GraphQLScalarType({
name: 'DateTime',
description: 'DateTime custom scalar type',
serialize(value) {
if (value instanceof Date) {
return value.toISOString();
}
throw Error('GraphQL Date Scalar serializer expected a `Date` object');
},
parseValue(value) {
if (typeof value === 'string') {
return new Date(value);
}
throw new Error('GraphQL Date Scalar parser expected a `string`');
},
parseLiteral(ast) {
if (ast.kind === Kind.STRING) {
return new Date(ast.value);
}
throw new Error('GraphQL Date Scalar invalid');
},
});
const resolvers = {
DateTime: datetimeScalar,
Query: {
users: () => users,
user(obj, args, context, info) {
for (let user of users) {
if (user.registerDateTime.getTime() == args.registerDateTime.getTime()) {
return user;
}
}
return null;
},
},
Mutation: {
createUser(obj, args, context, info) {
let user = { id: users.length + 1, name: args.name, email: args.email, registerDateTime: args.registerDateTime };
users.push(user);
return user;
}
}
};
module.exports = resolvers;
处理器文件主要包括:
创建 server.js 文件,内容如下:
const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
const fs = require("fs");
const typeDefs = fs.readFileSync('./schema.graphql').toString();
const resolvers = require('./resolvers');
const server = new ApolloServer({
typeDefs,
resolvers,
});
startStandaloneServer(server).then(function(data) {
console.log(`🚀 Server ready at ${data.url}`);
});
node server.js
服务启动后,访问 http://localhost:4000 进行测试。
执行变更操作的时候会调用 GraphQLScalarType 类 parseValue 方法。
mutation createUser($name: String!, $email: String!, $registerDateTime: DateTime!) {
createUser(name: $name, email: $email, registerDateTime: $registerDateTime) {
id,
name,
email
registerDateTime
}
}
{
"name": "newuser",
"email": "newuser@gmail.com",
"registerDateTime": "2000-01-01T10:10:10.000Z"
}
{
"data": {
"createUser": {
"id": "4",
"name": "newuser",
"email": "newuser@gmail.com",
"registerDateTime": "2000-01-01T02:10:10.000Z"
}
}
}
执行列表查询操作的时候会调用 GraphQLScalarType 类 serialize 方法。
query GetUsers {
users {
id,
name,
email,
registerDateTime
}
}
{
"data": {
"users": [
{
"id": "1",
"name": "user1",
"email": "user1@gmail.com",
"registerDateTime": "2000-01-01T10:10:10.000Z"
},
{
"id": "2",
"name": "user2",
"email": "user2@gmail.com",
"registerDateTime": "2000-01-01T10:10:10.000Z"
},
{
"id": "3",
"name": "user3",
"email": "user3@gmail.com",
"registerDateTime": "2000-01-01T10:10:10.000Z"
}
]
}
}
执行对象查询操作的时候会调用 GraphQLScalarType 类 parseLiteral 方法,主要用了处理查询请求中 hard code 的 registerDateTime 参数。
query FindUser {
user(registerDateTime: "2000-01-01T10:10:10.000Z") {
id,
name,
email,
registerDateTime
}
}
{
"data": {
"user": {
"id": "1",
"name": "user1",
"email": "user1@gmail.com",
"registerDateTime": "2000-01-01T10:10:10.000Z"
}
}
}