As many others, I'm trying to create my own Date
scalar using GraphQL with JavaScript. I've read many examples and followed this guide from apollo in particular.
scalar Date
to my schemaGraphQLScalarType
, with my implementations of serialize, parseValue and parseLiteral. I called that instance dateScalar
Date
and its value is dateScalar
This should make my Date
ready to be used according to what I've read. However, the value I get every time I do a query is exactly the same value that I have stored in the database. If that was a string, I see a string, if that was a number, I see a number. It's not parsed or serialized at any moment.
This is how my files look like.
schema.js
const { buildSchema } = require('graphql');
const schema = buildSchema(`
scalar Date
# more schema
`);
module.exports = schema;
root.js
const { dateScalar } = require('./customScalars');
const root = {
// queries
// mutations
// scalars
Date: dateScalar
};
module.exports = root;
customScalars.js
const { GraphQLScalarType } = require('graphql');
const dateScalar = new GraphQLScalarType({
name: 'Date',
description: 'This is a scalar version of the js Date',
serialize(value) {
console.log('call serialize');
return value.getTime();
},
parseValue(value) {
console.log('call parseValue');
return new Date(value).getFullYear();
},
parseLiteral(ast) {
console.log('call parseLiteral');
return;
}
});
module.exports = {
dateScalar
};
server.js
const express = require('express');
const graphqlHTTP = require('express-graphql');
const schema = require('./graphql/schema.js');
const graphqlRoot = require('./graphql/root.js');
var app = express();
app.use('/endpoint', graphqlHTTP({
schema: schema,
graphiql: true,
rootValue: graphqlRoot,
}));
app.listen(3333, () => console.log('Now browse to localhost:3333/endpoint'));
serialize
, etc, and none of them is called.Date
property from the root, and the behaviour is exactly the samedateScalar
does what I expect. I've done so by calling console.log(dateScalar.serialize(new Date().getTime()))
just after importing it in different files. When doing that I get the log telling me that serialize was called, and the result is what I was expecting.It seems like at the root it never linked the scalar from my schema with my custom scalar instance. Maybe I'm doing something wrong here?
My guess is that GraphQL is serializing and parsing using .toString()
, as it doesn't find my implementations for serializing/parsing.
Any ideas about how to make GraphQL use my custom scalar?
use graphql-tools
to make an executable schema and use apollo-server-express
instead of express-graphql
Unfortunately I'm not familiar with express-graphql
. So my solution requires replaching it with apollo-server-express
. Luckily it doesn't require many changes.
This is what works for me with some modifications to match your code.
Install packages first:
npm install apollo-server-express graphql-tools
And here's the code:
const {makeExecutableSchema} = require('graphql-tools')
const {graphqlExpress} = require('apollo-server-express');
const graphqlRoot = require('./graphql/root.js');
//...
const schemaDef = `
scalar Date
# more schema
`;
//build the schema
const schema = makeExecutableSchema({
typeDefs: [schemaDef],
resolvers: graphqlRoot
});
// your new endpoint:
app.use('/endpoint', bodyParser.json(), graphqlExpress({ schema }));
Read more about Adding a GraphQL endpoint
Also, with Apollo it is easy to have multiple schema files and resolvers files without having to worry about combining them manually. Here's an explanation from the documentation: Modularizing the schema