Categories
GraphQL JavaScript

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.

Categories
GraphQL JavaScript

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 JavaScript

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 JavaScript

More GraphQL Schemas and Types

GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.

In this article, we’ll look at some GraphQL data types including lists, required fields, interfaces, union types, and input types.

Lists and Non-Null

A non-null type can be created by using the ! type modifier.

With that added, it’ll make sure that we have to include the field when we’re making a query to the server.

The non-null modifier can be used for defining arguments for a field, which causes the GraphQL server to return a validation error if a null value is passed as that argument.

Lists work in a similar way. We can use square brackets to mark something as a list.

For example, we can use them together as follows:

type Person {  
  name: String!  
  addresses: [Address]!  
}

In the code above, we marked the name field as required and have the String type. Also, we have an addresses field which is a list of Address objects, and it’s also marked as required.

If we have something like:

myField: [String!]

This means that the list itself can be null, but myField can’t have any null members.

On the other hand, if we have:

myField: [String]!

then the list itself can’t be null, but it can contain null values.

We can nest any number of non-null and list modifiers according to our needs.

Interfaces

An interface is an abstract type that includes a certain set of fields that a type must include to implement the interface.

For example, we can create an interface as follows:

interface Person {  
  id: ID!  
  name: String!  
  friends: [Person]  
}

This means that a type that implements Person must have the exact fields as we listed above.

For example, we can create a type that implements the interface as follows:

type Employee implements Person{  
  id: ID!  
  name: String!  
  friends: [Person],  
  employeeId: String!  
}

In the code above, we have the Employee type that has all the fields above. We also have the employeeId string.

Therefore, we can use interfaces to ensure that a type has at least the fields and types that are listed in the interface.

To query something with various types that are implemented by an interface, we can use inline fragments as follows:

query Employee($id: ID!) {  
  employee(id: $id) {  
    name  
    ... on Employee {  
      employeeId  
    }  
  }  
}

Union types

Unio types are similar to interfaces, but they don’t get to specify any common fields between types.

We can define a union type with the union keyword as follows:

union Worker = Person | Employee

We’ll need to use a conditional fragment to be able to query any fields:

{  
  search(text: "an") {  
    __typename  
    ... on Person {  
      name  
    }  
    ... on Employee{  
      name  
      employeeId  
    }  
  }  
}

The __typename field is a String that indicates the type of the response object.

Input types

We can create input types to pass in whole objects into a request. For example, we can define an input type as follows:

input PersonInput {  
  firstName: String!  
  lastName: String!  
}

Then we can pass it into a mutation as follows:

mutation CreatePerson($person: PersonInput!) {  
  createReview(person: $person) {  
    firstName  
    lastName  
  }  
}

The fields on an input object can refer to input object types, but we can’t mix input and output types in our schema. Input object types also can’t have arguments in their fields.

Conclusion

To make sure a field isn’t null we can use the exclamation mark to mark it non-null.

We can also use square brackets to mark that something is a list.

To define a list of set fields for types, we can use interfaces to make sure all types that implement an interface have the fields listed.

Union types are useful for letting us combine common fields of types that implement the same interface and avoid repeating fields in queries.

We can use input types to pass in whole objects into a mutation.

Categories
GraphQL JavaScript Nodejs

An Introduction to GraphQL

GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.

In this article, we’ll look at how to make basic queries to a GraphQL API.

Defining the API

We define an API by defining the types and fields for those types and provide functions for each field on each type.

For example, if we have the following type:

type Query {  
  person: Person  
}

Then we have to create a function for the corresponding type to return the data:

function Query_person(request) {  
  return request.person;  
}

Making Queries

Once we have a GraphQL service running, we can send GraphQL queries to validate and execute on the server.

For example, we can make a query as follows:

{  
  person {  
    firstName  
  }  
}

Then we may get JSON like the following:

{  
  "person": {  
    "firstName": "Joe"  
  }  
}

Queries and Mutations

Queries are for getting data from the GraphQL server and mutations are used for manipulating data stored on the server.

For example, the following is a query to get a person’s name:

{  
  person {  
    name  
  }  
}

Then we may get the following JSON from the server:

{  
  "data": {  
    "person": {  
      "name": "Joe"  
    }  
  }  
}

The field name returns a String type.

We can change the query as we wish if we want to get more data. For example, if we write the following query:

{  
  person {  
    name  
    friends {  
      name  
    }  
  }  
}

Then we may get something like the following as a response:

{  
  "data": {  
    "person": {  
      "name": "Joe",  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    }  
  }  
}

The example above has friends being an array. They look the same from the query perspectively, but the server knows what to return based on the type specified.

Arguments

We can pass in arguments to queries and mutations. We can do a lot more with queries if we pass in arguments to it.

For example, we can pass in an argument as follows:

{  
  person(id: "1000") {  
    name      
  }  
}

Then we get something like:

{  
  "data": {  
    "person": {  
      "name": "Luke"  
    }  
  }  
}

from the server.

With GraphQL, we can pass in arguments to nested objects. For example, we can write:

{  
  person(id: "1000") {  
    name  
    height(unit: METER)  
  }  
}

Then we may get the following response:

{  
  "data": {  
    "person": {  
      "name": "Luke",  
      "height": 1.9  
    }  
  }  
}

In the example, the height field has a unit which is an enum type that represents a finite set of values.

unit may either be METER or FOOT.

Fragments

We can define fragments to let us reuse complex queries.

For example, we can define a fragment and use it as follows:

{  
  leftComparison: person(episode: FOO) {  
    ...comparisonFields  
  }  
  rightComparison: person(episode: BAR) {  
    ...comparisonFields  
  }  
}  
​  
fragment comparisonFields on Character {  
  name  
  appearsIn  
  friends {  
    name  
  }  
}

In the code above, we defined the comparisonFields fragment which has the list of fields we want to include in each query.

Then we have the leftComparison and rightComparison queries which include the fields of the comparisonFields fragment by using the ... operator.

Then we get something like:

{  
  "data": {  
    "leftComparison": {  
      "name": "Luke",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    },  
    "rightComparison": {  
      "name": "Mary",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Mary"  
        },  
        {  
          "name": "Alex"  
        }  
      ]  
    }  
  }  
}

Using variables inside fragments

We can pass in variables into fragments as follows:

query PersonComparison($first: Int = 3){  
  leftComparison: person(episode: FOO) {  
    ...comparisonFields  
  }  
  rightComparison: person(episode: BAR) {  
    ...comparisonFields  
  }  
}  
​  
fragment comparisonFields on Character {  
  name  
  appearsIn  
  friends(first: $first) {  
    name  
  }  
}

Then we may get something like:

{  
  "data": {  
    "leftComparison": {  
      "name": "Luke",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    },  
    "rightComparison": {  
      "name": "Mary",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Mary"  
        },  
        {  
          "name": "Alex"  
        }  
      ]  
    }  
  }  
}

as a response.

The operation type may either be a query, mutation, or subscription and describes what operator we’re intending to do. It’s required unless we’re using the query shorthand syntax. In that case, we can’t supply a name or variable definition for our operation.

The operation name is a meaningful and explicit name for our operation. It’s required in multi-operation documents. But its use is encouraged because it’s helpful for debugging and server-side logging.

It’s easy to identify the operation with a name.

Conclusion

GraphQL is a query language that lets us send requests to a server in a clear way. It works by sending nested objects with operation type and name along with any variables to the server.

Then the server will return us the response that we’re looking for.

Operation types include queries for getting data and mutations for making changes to data on the server.