Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom scalar types in GraphQL schema language? #497

Closed
ggregoire opened this issue Sep 21, 2016 · 9 comments
Closed

Custom scalar types in GraphQL schema language? #497

ggregoire opened this issue Sep 21, 2016 · 9 comments

Comments

@ggregoire
Copy link

ggregoire commented Sep 21, 2016

Hi,

I tried to use a custom scalar type Date in my schema, written with the GraphQL schema language.

It seems that buildSchema takes only one param.
Is there a way to "register" my custom type in order to let buildSchema know what is the Date type?

import { buildSchema } from 'graphql';
import { GraphQLScalarType } from 'graphql/type';

const Date = new GraphQLScalarType({
  name: 'Date',
  serialize(value) {
    return value;
  },
});

const schema = buildSchema(`
  scalar Date

  type User {
    id: Int
    firstName: String
    lastName: String
    sex: String
    birthDate: Date
  }

  type Query {
    users(id: Int): [User]
  }
`);

const root = {
  users: async ({ id }) => {
    const users = db('users');
    return await id ? users.where('id', id) : users;
  },
}

The value of birthDate is 1986-02-11 07:13:14. I expect the same after the serialization.

My query in graphiQL:

{
  users(id: 1) {
    id
    firstName
    lastName
    sex
    birthDate
  }
}

The result:

{
  "data": {
    "users": [
      {
        "id": 1,
        "firstName": "Midas",
        "lastName": "Bokma",
        "sex": "m",
        "birthDate": null
      }
    ]
  },
  "errors": [
    {
      "message": "Expected a value of type \"Date\" but received: Tue Feb 11 1986 07:13:14 GMT-0600 (CST)",
      "locations": [
        {
          "line": 7,
          "column": 5
        }
      ]
    }
  ]
}
@ggregoire ggregoire changed the title Use custom scalar types in GraphQL schema language? Custom scalar types in GraphQL schema language? Sep 21, 2016
@helfer
Copy link
Contributor

helfer commented Sep 21, 2016

@ggregoire That won't work, because the const Date and the type Date won't refer to the same thing. buildSchema isn't really intended for making executable schemas, if you want to do that, you can use a library like graphql-tools instead.

@ggregoire
Copy link
Author

ggregoire commented Sep 21, 2016

Maybe not the right place to continue the discussion, but I got this error

Error: Type "Date" not found in document.

with the following simple code (almost a copy/paste of graphql-tools documentation)

makeExecutableSchema({
  typeDefs: [`
    scalar Date

    type User {
      id: Int
      firstName: String
      lastName: String
      sex: String
      birthDate: Date
    }

    type Query {
      users(id: Int): [User]
    }
  `],
  resolvers: {
    Query: {
      async users({ id }) {
        const users = db('users');
        return await id ? users.where('id', id) : users;
      }
    },
    Date: {
      __parseValue(value) {
        return new Date(value); // value from the client
      },
      __serialize(value) {
        return value.getTime(); // value sent to the client
      },
      __parseLiteral(ast) {
        if (ast.kind === Kind.INT) {
          return parseInt(ast.value, 10); // ast value is always in string format
        }
        return null;
      }
    },
  }
});

@helfer
Copy link
Contributor

helfer commented Sep 21, 2016

@ggregoire yeah, you should open an issue on graphql-tools. But for what it's worth, I copy-pasted your exact code and it created a schema with the Date type just fine, so I'm not sure what's going on.

@ggregoire
Copy link
Author

My bad, I let this in my code 🙄

const officialWay = buildSchema(`
  type User {
    id: Int
    firstName: String
    lastName: String
    sex: String
    birthDate: Date
  }

  type Query {
    users(id: Int): [User]
  }
`);

@helfer Thank you for the help!

@ffxsam
Copy link

ffxsam commented May 23, 2017

@helfer I'm having the same exact issue @ggregoire was in the first post, but I can't make sense out of what transpired on this thread. makeExecutableSchema is from a module by Apollo, buildSchema appears to be official GraphQL. How is the official GraphQL schema builder not sufficient for creating a custom Date scalar? My schema looks like this:

module.exports = buildSchema(`
  # A JavaScript Date object.
  scalar DateTime

  # A geoframe object, which contains several polygons.
  type Geoframe {
    id: ID!
    # Device ID count.
    count: Int
    createdAt: DateTime!
    createdBy: User!
    polygons: [Polygon]
  }

  type Query {
    geoframes: [Geoframe]
  }
`);

The resolvers:

module.exports = {
  DateTime: new GraphQLScalarType({
    name: 'DateTime',
    description: 'Date custom scalar type',
    parseValue(value) {
      return new Date(value); // value from the client
    },
    serialize(value) {
      return value.getTime(); // value sent to the client
    },
    parseLiteral(ast) {
      if (ast.kind === Kind.INT) {
        return parseInt(ast.value, 10); // ast value is always in string format
      }
      return null;
    },
  }),
  geoframes() {
    return new Promise((resolve, reject) => {
      Geoframe.find({}, (err, docs) => {
        const newDocs = docs.map(doc =>
          Object.assign({}, doc.toObject(), {
            createdAt: doc._id.getTimestamp(),
          })
        );

        resolve(newDocs);
      });
    });
  },
};

@klebba
Copy link

klebba commented Dec 14, 2017

@ffxsam What approach did you land on? I agree that it is bizarre that there is no obvious solution beyond going outside the library.

Edit: here's a solution:

https://stackoverflow.com/questions/47824603/graphql-custom-scalar-definition-without-graphql-tools

@mrdulin
Copy link

mrdulin commented Apr 18, 2018

@ffxsam Hi.

parseValue(value) {
  return new Date(value); // value from the client
},

What does value from the client mean?

@ffxsam
Copy link

ffxsam commented Apr 19, 2018

@mrdulin The GraphQL client side. So, for example, if Apollo sends a mutation to the GraphQL server to update a date value.

@christopher-caldwell
Copy link

@ffxsam What approach did you land on? I agree that it is bizarre that there is no obvious solution beyond going outside the library.

Edit: here's a solution:

https://stackoverflow.com/questions/47824603/graphql-custom-scalar-definition-without-graphql-tools

The solution in the post worked for me, although with v15.3.0 ( not latest ), I had to do: Object.assign(schema.getTypeMap().Date, DateScalar)

I feel like this should be better documented. Every example I could find on google, SO, etc was with Apollo. The scalar section of the docs is very small, and doesn't cover this at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants