node.jsgraphqlapollographql-js

GraphQL not calling custom scalar methods


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.

What I've done

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'));

My debug so far

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?


Solution

  • tl;dr

    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