Categories
GraphQL

Creating GraphQL Input Types with Express-GraphQL

With GraphQL, we can create scalar types as we do with object types and other compound data types.

In this article, we’ll look at how to create GraphQL input types with the GraphQLInputObjectType constructor.

GraphQLInputObjectType Constructor

We can use the GraphQLInputObjectType constructor to create a new input type.

To do this, we pass in an object to the GraphQLInputObjectType constructor with the name property to set the name of our input type, and then a fields object with the field names as the keys and the values are objects with the type property to specify the types of the fields.

To specify a required field, we use the GraphQLNonNull constructor. Also, we can specify a default value by specifying a value for the defaultValue property.

For example, we can specify a mutation as follows:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const graphql = require('graphql');

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}

const PersonInputType = new graphql.GraphQLInputObjectType({
  name: 'PersonInput',
  fields: {
    firstName: { type: new graphql.GraphQLNonNull(graphql.GraphQLString) },
    lastName: { type: new graphql.GraphQLNonNull(graphql.GraphQLString) },
  }
});

const PersonType = new graphql.GraphQLObjectType({
  name: 'Person',
  fields: {
    firstName: { type: graphql.GraphQLString },
    lastName: { type: graphql.GraphQLString },
  }
});

let person = new Person('Jane', 'Smith');

const mutationType = new graphql.GraphQLObjectType({
  name: 'Mutation',
  fields: {
    createPerson: {
      type: PersonType,
      args: {
        person: {
          type: new graphql.GraphQLNonNull(PersonInputType),
        },
      },
      resolve: (_, { person: { firstName, lastName } }) => {
        person = new Person(firstName, lastName);
        return person;
      }
    }
  }
});

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    person: {
      type: PersonType,
      resolve: () => {
        return person;
      }
    }
  }
});

const schema = new graphql.GraphQLSchema({ query: queryType, mutation: mutationType });

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  graphiql: true,
}));

app.listen(3000, () => console.log('server started'));

In the code above, we created the PersonInputType input type as follows:

const PersonInputType = new graphql.GraphQLInputObjectType({
  name: 'PersonInput',
  fields: {
    firstName: { type: new graphql.GraphQLNonNull(graphql.GraphQLString) },
    lastName: { type: new graphql.GraphQLNonNull(graphql.GraphQLString) },
  }
});

We used the GraphQLInputObjectType constructor and we pass in an object with the name field with value 'PersonInput' to specify the name of the type.

Then in the fields property, we specified that the type has a firstName and lastName field, each of which is required since we used the GraphQLNonNull constructor with the GraphQLString type passed into it.

Input types can only be used with mutations.

We then create a mutation that takes a PersonInputType argument as follows:

const mutationType = new graphql.GraphQLObjectType({
  name: 'Mutation',
  fields: {
    createPerson: {
      type: PersonType,
      args: {
        person: {
          type: new graphql.GraphQLNonNull(PersonInputType),
        },
      },
      resolve: (_, { person: { firstName, lastName } }) => {
        person = new Person(firstName, lastName);
        return person;
      }
    }
  }
});

In the code above, we created a createPerson mutation with the type specifying the output type, which is the PersonType which we specified in the code.

In the args property, we specified the person argument with the type set to the PersonInputType . This specifies that out mutation takes the PersonInuptType input type object.

Then in our resolve function, we get the firstName and lastName from the args parameter in the second parameter and created a new Person object, set it to person and returns it.

All GraphQL server apps have to have a root query type, so we also specified a queryType as follows:

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    person: {
      type: PersonType,
      resolve: () => {
        return person;
      }
    }
  }
});

We return a Person object and returns the person variable.

Then when we make a mutation as follows:

mutation {
  createPerson(person: {firstName: "John", lastName: "Doe"}){
    firstName
    lastName
  }
}

We get:

{
  "data": {
    "createPerson": {
      "firstName": "John",
      "lastName": "Doe"
    }
  }
}

as the response.

When we make a query as follows:

{
  person {
    firstName
    lastName
  }
}

We get back:

{
  "data": {
    "person": {
      "firstName": "John",
      "lastName": "Doe"
    }
  }
}

Conclusion

We can create a GraphQL input type with the GraphQLInputObjectType constructor with the name and fields properties passed in together in one object to the constructor.

The name field has the name and the fields object has fields and the type.

We can use the GraphQLNonNull to specify that a field is required.

Then in our mutation, we specify the input data type in the args property.

Categories
GraphQL

Creating GraphQL Scalar Types with Express-GraphQL

With GraphQL, we can create scalar types as we do with create object types and other compound data types.

In this article, we’ll look at how to create scalar types with Express-GraphQL.

GraphQLScalarType

We can create a GraphQL scalar type with the GraphQLScalarType constructor. To create a scalar type, we have to give it a name, an optional description, and ways to serialize and parse the values.

The constructor takes an object with the following fields:

  • name — the name of the scalar type we want to define as a string
  • description — an optional string with the description of our type
  • serialize — a function that takes in a value parameter, which can be anything and then return something that we want to transform it to for transmission
  • parseValue — an optional function that takes a value parameter, which can be anything and then return the parsed value as we wish to
  • parseLiteral — a function that takes an abstract syntax tree object, which is the value of the literal, then we return something that we want to transform the value to.

Example

For example, we can write the following to create a scalar type and return it in the response:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const graphql = require('graphql');

const dateValue = (value) => {
  if (value instanceof Date) {
    return +value;
  }
}

const DateType = new graphql.GraphQLScalarType({
  name: 'Date',
  serialize: dateValue,
  parseValue: dateValue,
  parseLiteral(ast) {
    return dateValue(ast.value);
  }
});

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    currentDate: {
      type: DateType,
      resolve: () => {
        return new Date();
      }
    }
  }
});

const schema = new graphql.GraphQLSchema({ query: queryType });

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  graphiql: true,
}));

app.listen(3000, () => console.log('server started'));

In the code above, we defined the dateValue function as follows:

const dateValue = (value) => {
  if (value instanceof Date) {
    return +value;
  }
}

In the function, we check if the value is created from the Date constructor, if it is, then we return the Date object converted to a timestamp.

Then we use it to create a new scalar type called Date as follows:

const DateType = new graphql.GraphQLScalarType({
  name: 'Date',
  serialize: dateValue,
  parseValue: dateValue,
  parseLiteral(ast) {
    return dateValue(ast.value);
  }
});

We passed in the name, which is 'Date' . Then we have the serialize property with the dateValue to return the timestamp as the serialized version of the scalar type.

Likewise, we parse the Date object into a UNIX timestamp with the same function.

In the parseLiteral function, we pass in the value to the dateValue function to convert the Date object into a UNIX timestamp.

Then we create our query type so that we can return the timestamp response to the user as follows:

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    currentDate: {
      type: DateType,
      resolve: () => {
        return new Date();
      }
    }
  }
});

We create the Query object type so that we can query it and then in the fields property, we return a currentDate field that’s of the Date scalar type that we defined earlier.

In the resolve method, we just return new Date() , which will automatically parsed into a UNIX timestamp in the response since that’s how we decided to serialize it in the dateValue function.

Then when we make a query as follows:

{
  currentDate
}

we get something like:

{
  "data": {
    "currentDate": 1579464244268
  }
}

where the currentDate is replaced with the current UNIX timestamp.

Conclusion

We can create a scalar type by using the GraphQLScalarType constructor.

To define one, we have to pass in functions to serialize and parse values as we wish to.

Categories
GraphQL

Creating a GraphQL Server with Express and Apollo Server

Apollo Server is available as a Node package. We can use it to create a server to accept GraphQL requests.

In this article, we’ll look at how to use it with Express to create our own GraphQL server.

Get started with Apollo Server

We get started by installing the express-apollo-server.

To install it with Express, we run:

npm install apollo-server-express express

Then create an index.js file and add:

const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');

const books = [
  {
    title: 'JavaScript for Dummies',
    author: 'Jane Smith',
  },
  {
    title: 'JavaScript Book',
    author: 'Michael Smith',
  },
];

const typeDefs = gql`
  type Book {
    title: String
    author: String
  }

  type Query {
    books: [Book]
  }
`;

const resolvers = {
  Query: {
    books: () => books,
  },
};

const app = express();
const server = new ApolloServer({ typeDefs, resolvers });
server.applyMiddleware({ app });

app.listen(3000, () => console.log('server started'));

In the code above, we created our basic Apollo GraphQL server by creating our data in the books array.

Then we used the gql tag with our schema definition string passed in to create our schema and assigned it to the typedefs constant.

The query type is always required so we can query data from our server. The server won’t run without it.

We created a Book type with fields title and author . Then we created a books query to return an array of Books.

Next, we created our resolvers so that we can query the data we created. We just created a books resolve to return the books array.

Finally, we have the following initialization code to load the server:

const app = express();
const server = new ApolloServer({ typeDefs, resolvers });
server.applyMiddleware({ app });

app.listen(3000, () => console.log('server started'));

Then when we go to /graphql in our browser, we see a UI to test our query.

To run the server, we run:

node index.js

We can test our server by running:

{
  books {
    title
    author
  }
}

Then when we click the arrow button in the middle, we should get:

{
  "data": {
    "books": [
      {
        "title": "JavaScript for Dummies",
        "author": "Jane Smith"
      },
      {
        "title": "JavaScript Book",
        "author": "Michael Smith"
      }
    ]
  }
}

as the response.

Conclusion

We created a simple Apollo GraphQL server with Express by installing the express and express-apollo-server packages.

Then we created the type definition by passing a string with the type definitions into the gql tag.

Once we did that, we created a resolver to return the response which is mapped from the query.

Then we run the server to make the query and return the data. We can test that by going to the /graphql page that comes with the Express Apollo server.

Categories
GraphQL

Authentication and Express Middleware with GraphQL

We can create a simple GraphQL server with Express. To do this, we need the express-graphql and graphql packages.

In this article, we’ll look at how to use middleware with Express GraphQL.

Express Middleware

We can use Express middlewares as usual if we use express-graphql to build our GraphQL server with Express.

The request object is available as the second argument in any resolver.

For example, if we want to get the hostname of a request in our resolver, we can write:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');

const schema = buildSchema(`
  type Query {
    hostname: String
  }
`);

const loggingMiddleware = (req, res, next) => {
  console.log(req.hostname);
  next();
}

const root = {
  hostname(args, request) {
    return request.hostname;
  }
};

const app = express();
app.use(loggingMiddleware);
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(3000, () => console.log('server started'));

In the code above, we created our schema as usual to get the hostname of the app.

Then we added our loggingMiddleware to log the hostname. It calls next so we can use our graphqlHTTP middleware.

Then in our root resolver, we added a hostname method, which takes the request parameter as the second argument, which has the Express request object.

This is where we can return the hostname property from request so that we can return it in the response.

This means that we can continue to use middleware to handle authentication as we did with REST APIs.

Popular authentication options for Express include Passport, express-jwt , and express-session .

Authentication

We can use jsonwebtoken in our Express GraphQL server as follows to add authentication via JSON web token.

To do this, we first install jsonwebtoken by running:

npm i `jsonwebtoken`

Then we can include it in our app and then add it to our Express GraphQL server as follows:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const jwt = require('jsonwebtoken');
const unless = require('express-unless');

const schema = buildSchema(`
  type Query {
    hostname: String
  }
`);

const root = {
  hostname(args, request) {
    return request.hostname;
  }
};

const verifyToken = (req, res, next) => {
  jwt.verify(req.headers.authorization, 'secret', (err, decoded) => {
    if (err){
      return res.send(401);
    }
    next();
  });
}
verifyToken.unless = unless;

const app = express();
app.post('/auth', (req, res) => {
  const token = jwt.sign({ foo: 'bar' }, 'secret');
  res.send(token);
})

app.use(verifyToken.unless({ path: ['/auth'] }));
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(3000, () => console.log('server started'));

In the code above, we have the verifyToken middleware to verify the token that’s issued by our auth route.

In verifyToken , we called jwt.verify to verify the token that we passed into the Authorization header. If we get an error, then we send a 401 response.

Otherwise, we call next to proceed to the next middleware our route.

In the auth route, we issue our authentication token by calling jwt.sign with whatever content we want as the first argument and the token’s secret in the second argument.

Also, we excluded the verifyToken middleware from the auth route by using the express-unless middleware.

We did that by assigning unless to verifyToken.unless .

Then now when we want to make a request to our GraphQL server via the /graphql route, we have to pass in our auth token to the Authorization header.

This keeps our GraphQL requests more secure. However, we should have an encrypted secret if we’re going to JSON web tokens in the real world.

Conclusion

We can use Express middleware for logging, authentication, or whatever we need them for.

To include middleware, we just call the app.use method as usual.

We can exclude routes from using the middleware with the express-unless package.

To add authentication via JSON web tokens, we can use the jsonwebtoken package to add token issuing and verification capabilities to our Express GraphQL server.

Categories
GraphQL

Adding Mutations with Express GraphQL

We can create a simple GraphQL server with Express. To do this, we need the express-graphql and graphql packages.

In this article, we’ll look at how to create mutations and input types with Express and GraphQL.

Mutations and Input Types

To create mutations, we create a schema that has the Mutation type rather than a Query .

Then it’s a simple as making the API endpoint part of the top-level Mutation type instead of a Query type.

Both mutations and queries can be handled by root resolvers.

We can then create a GraphQL server that takes both queries and mutations as follows:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const crypto = require('crypto');
const schema = buildSchema(`
  input TodoInput {
    text: String
  }

  type Todo {
    id: ID!
    text: String
  }

  type Query {
    getTodo(id: ID!): Todo
  }

  type Mutation {
    createTodo(input: TodoInput): Todo
    updateTodo(id: ID!, input: TodoInput): Todo
  }
`);

class Todo {
  constructor(id, { text }) {
    this.id = id;
    this.text = text;
  }
}

let todos = {};

const root = {
  getTodo: ({ id }) => {
    if (!todos[id]) {
      throw new Error('Todo not found.');
    }
    return new Todo(id, todos[id]);
  },
  createTodo: ({ input }) => {
    const id = crypto.randomBytes(10).toString('hex');
    todos[id] = input;
    return new Todo(id, input);
  },
  updateTodo: ({ id, input }) => {
    if (!todos[id]) {
      throw new Error('Todo not found');
    }
    todos[id] = input;
    return new Todo(id, input);
  },
};

const app = express();

app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(3000, () => console.log('server started'));

In the code above, we defined our types by writing:

const schema = buildSchema(`
  input TodoInput {
    text: String
  }

  type Todo {
    id: ID!
    text: String
  }

  type Query {
    getTodo(id: ID!): Todo
  }

  type Mutation {
    createTodo(input: TodoInput): Todo
    updateTodo(id: ID!, input: TodoInput): Todo
  }
`);

We created the input type TodoInput and the Todo type. Then we created the Query type with the getTodo member so that we can get our todo items.

Then in our Mutation , we added the createTodo and updateTodo members so that we can add and update todos.

Then we create our Todo class so that we can store the todo data:

class Todo {
  constructor(id, { text }) {
    this.id = id;
    this.text = text;
  }
}

Next, we have our root resolver:

const root = {
  getTodo: ({ id }) => {
    if (!todos[id]) {
      throw new Error('Todo not found.');
    }
    return new Todo(id, todos[id]);
  },
  createTodo: ({ input }) => {
    const id = crypto.randomBytes(10).toString('hex');
    todos[id] = input;
    return new Todo(id, input);
  },
  updateTodo: ({ id, input }) => {
    if (!todos[id]) {
      throw new Error('Todo not found');
    }
    todos[id] = input;
    return new Todo(id, input);
  },
};

It adds the functions with the same as we specified in our schema so that we can do something when we make some queries.

In this example, getTodo , we’ll return the todo with the given id .The todo that’s found will be returned. Otherwise, we throw an error.

In createTodo , we get the input from the query and then add the todo entry to our todos object, which is our fake database to store the todos. The todo that’s saved will be returned.

Then we have the updateTodo function to update the todo by id . Whatever has the given id will be replaced with the content of input . The todo that’s saved will be returned. We throw an error if a todo with the given id isn’t found.

Then when we go to the /graphql page, we can type in the following to the GraphiQL window:

mutation {
  createTodo(input: {text: "eat"}) {
    id
    text
  }
}

Then we get something like:

{
  "data": {
    "createTodo": {
      "id": "c141d1fda69e8d9084bd",
      "text": "eat"
    }
  }
}

as the response.

If we make a query for updating todo as follows:

mutation {
  updateTodo(id: "e99ce10750c93793a23d", input: {text: "eat"}) {
    id
    text
  }
}

We get something like:

{
  "data": {
    "updateTodo": {
      "id": "e99ce10750c93793a23d",
      "text": "eat"
    }
  }
}

back as the response.

If a todo isn’t found, then we get:

{
  "errors": [
    {
      "message": "Todo not found",
      "locations": [
        {
          "line": 9,
          "column": 3
        }
      ],
      "path": [
        "updateTodo"
      ]
    }
  ],
  "data": {
    "updateTodo": null
  }
}

as the response.

We can make the getTodo query as follows:

query {
  getTodo(id: "e99ce10750c93793a23d"){
    id
    text
  }
}

Then we get:

{
  "data": {
    "getTodo": {
      "id": "e99ce10750c93793a23d",
      "text": "eat"
    }
  }
}

as the response.

Conclusion

We can create mutations as we do with queries.

To accept mutation operations in our GraphQL server, we make our types for storing our data, then we create our mutations by populating the Mutation type with our members.

We can then use the buildSchema function to build the schema we just specified.

Then in our root reducer, we make the functions that with the names that we specified in the type definitions.

Finally, we can make queries to our server to run the mutations.