Categories
GraphQL

React Tips — GraphQL Queries, URL Parameters and React Router

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

Make GraphQL Queries with React Apollo

We can make GraphQL queries with React Apollo by using the client.query method.

This is available once we update the component by calling withApollo function.

For instance, we can write:

class Foo extends React.Component {
  runQuery() {
    this.props.client.query({
      query: gql`...`,
      variables: {
        //...
      },
    });
  }

  render() {
    //...
  }
}

export default withApollo(Foo);

The client.query method will be available in the props once we call withApollo with our component to return a component.

The method takes an object that has the query and variables properties.

The query property takes a query object returned by the gql form tag.

variables has an object with variables that we interpolate in the query string.

We can also wrap our app with the ApolloConsumer component.

For example, we can write:

const App = () => (
  <ApolloConsumer>
    {client => {
      client.query({
        query: gql`...`,
        variables: {
          //...
        }
      })
    }}
  </ApolloConsumer>
)

We can make our query in here.

For function components, there’s the useApolloClient hook.

For instance, we can write:

const App = () => {
  const client = useApolloClient();
  //...
  const makeQuery = () => {
    client => {
      client.query({
        query: gql`...`,
        variables: {
          //...
        }
      })
    }
  }
  //...
}

The hook returns the client that we can use to make our query.

There’s also the useLazyQuery hook that we can use to make queries.

For instance, we can write:

const App = () => {
  const [runQuery, { called, loading, data }] = useLazyQuery(gql`...`)
  const handleClick = () => runQuery({
    variables: {
      //...
    }
  })
  //...
}

runQuery lets us make our query.

React Router Pass URL Parameters to Component

We can pass URL parameters if we create a route that allows us to pass parameters to it.

For instance, we can write:

const App = () => {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/foo">foo</Link>
          </li>
          <li>
            <Link to="/bar">bar</Link>
          </li>
          <li>
            <Link to="/baz">baz</Link>
          </li>
        </ul>

        <Switch>
          <Route path="/:id" children={<Child />} />
        </Switch>
      </div>
    </Router>
  );
}

function Child() {
  const { id } = useParams();

  return (
    <div>
      <h3>ID: {id}</h3>
    </div>
  );
}

We have a Child component that has the useParams hook.

It lets us get the URL parameters that we want and it’s passed in from navigation.

It returns the URL parameter as a key-value pair.

The keys are what we defined and the value is what we have passed when we navigate.

In App , we have the Link components with the paths.

And also we have the Switch components that have the route that takes the id URL parameter.

The Route has the route that we pass in. children has the component that’s displayed.

Preventing Form Submission in a React Component

There are several ways to prevent form submission in a React component.

If we have a button inside the form, we can make set the button’s type to be button.

For instance, we can write:

<button type="button" onClick={this.onTestClick}>click me</Button>

If we have a form submit handler function passed into the onSubmit prop;

<form onSubmit={this.onSubmit}>

then in th onSubmit method, we call preventDefault to stop the default submit behavior.

For example, we can write:

onSubmit (event) {
  event.preventDefault();
  //...
}

TypeScript Type for the Match Object

We can use the RouteComponentProps interface, which is a generic interface that provides some base members.

We can pass in our own interface to match more members if we choose.

For example, we can write:

import { BrowserRouter as Router, Route, RouteComponentProps } from 'react-router-dom';

interface MatchParams {
  name: string;
}

interface MatchProps extends RouteComponentProps<MatchParams> {}

const App = () => {
  return (
    <Switch>
      <Route
         path="/products/:name"
         render={({ match }: MatchProps) => (
            <Product name={match.params.name}
         /> )}
      />
    </Switch>
  );
}

We use the MatchProps interface that we created as the type for the props parameter in the render prop.

Then we can reference match.params as we wish.

Conclusion

We can make GraphQL queries in a React component with the React Apollo client.

React Router lets us pass in URL parameters easily.

It works with JavaScript and TypeScript.

We can prevent form submission with event.preventDefault() in the submit handler.

Categories
GraphQL

Constructing Types with the GraphQL Package

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 add types that we can use to build a schema with the graphql package.

Constructing Types

We can construct a schema programmatically with the GraphQLSchema constructor that comes with the graphql package.

Instead of defining Query and Mutation types using the schema language, we can create them as separate object types.

For example, we can write the following to create a type with the graphql.GraphQLObjectType constructor to create an object type programmatically:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const graphql = require('graphql');
const userType = new graphql.GraphQLObjectType({
  name: 'User',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
  }
});

let users = {
  '1': {
    id: '1',
    name: 'Jane'
  }
}

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    user: {
      type: userType,
      args: {
        id: { type: graphql.GraphQLString }
      },
      resolve: (_, { id }) => {
        return users[id];
      }
    }
  }
});

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

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 created the userType GraphQL data type by writing:

const userType = new graphql.GraphQLObjectType({
  name: 'User',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
  }
});

The name field defines the name of our type and the fields object has the fields that we include with the type. We defined id and name both to have type String .

Then we define our Query type with:

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    user: {
      type: userType,
      args: {
        id: { type: graphql.GraphQLString }
      },
      resolve: (_, { id }) => {
        return users[id];
      }
    }
  }
});

In the code above, we defined the name of the type to be Query . The fields we include is the user field, which is of type User that we defined above.

Also, we specified that we have the String id as the argument with the args property.

Finally, we have a resolve property with the resolver to return what we want to return.

In this case, we want to return the User from the users object given the id passed into the argument.

Then when we make the following query:

{
  user(id: "1"){
    id
    name
  }
}

We get back:

{
  "data": {
    "user": {
      "id": "1",
      "name": "Jane"
    }
  }
}

since we have the following in the users object:

let users = {
  '1': {
    id: '1',
    name: 'Jane'
  }
}

We can do the same with mutations.

This is particularly useful is we want to create a GraphQL schema automatically from something else like a database schema. We may have a common format for something like creating and updating database records.

It’s also useful for implementing features like union types that don’t map to ES6 constructs.

GraphQLUnionType

We can create union types with the GraphQLUnionType constructor.

To create a union type and use it in our app, we can use the GraphQLUnionType constructor as follows:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const graphql = require('graphql');
class Dog {
  constructor(id, name) {
    this.id = id;
    this.name = name;
  }
};

class Cat {
  constructor(id, name, age) {
    this.id = id;
    this.name = name;
    this.age = age;
  }
};

const DogType = new graphql.GraphQLObjectType({
  name: 'Dog',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
  }
});

const CatType = new graphql.GraphQLObjectType({
  name: 'Cat',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
    age: { type: graphql.GraphQLInt },
  }
});

const PetType = new graphql.GraphQLUnionType({
  name: 'Pet',
  types: [DogType, CatType],
  resolveType(value) {
    if (value instanceof Dog) {
      return DogType;
    }
    if (value instanceof Cat) {
      return CatType;
    }
  }
});

let pets = {
  '1': new Dog('1', 'Jane'),
  '2': new Cat('1', 'Jane', 11),
}

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    pet: {
      type: PetType,
      args: {
        id: { type: graphql.GraphQLString }
      },
      resolve: (_, { id }) => {
        return pets[id];
      }
    }
  }
});

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

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 created the Dog and Cat classes to serve as models for our data.

Then we create the GraphQL Dog and Cat types as follows:

const DogType = new graphql.GraphQLObjectType({
  name: 'Dog',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
  }
});
const CatType = new graphql.GraphQLObjectType({
  name: 'Cat',
  fields: {
    id: { type: graphql.GraphQLString },
    name: { type: graphql.GraphQLString },
    age: { type: graphql.GraphQLInt },
  }
});

We defined the DogType and CatType constants to define the Dog and Cat object types.

Dog has id and name fields and Cat has id , name , and age fields.

Then we defined the Pet union type, which is a union of Dog and Cat as follows:

const PetType = new graphql.GraphQLUnionType({
  name: 'Pet',
  types: [DogType, CatType],
  resolveType(value) {
    if (value instanceof Dog) {
      return DogType;
    }
    if (value instanceof Cat) {
      return CatType;
    }
  }
});

Note that we have an array of types and a resolveType method instead of the resolve method.

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

const queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: {
    pet: {
      type: PetType,
      args: {
        id: { type: graphql.GraphQLString }
      },
      resolve: (_, { id }) => {
        return pets[id];
      }
    }
  }
});

The resolve function gets the pets entry by id and returns it, and we specified that the type we return is the PetType .

Once we did that, we can make our query using inline fragments as follows:

{
  pet(id: "1"){
    __typename,
    ...on Dog {
      id
      name
    }
    ...on Cat {
      id
      name
      age
    }
  }
}

In the query above, we discriminated between the fields of Dog and Cat by using the ...on operator. __typename gets the type of the object returned.

With that query, we should get:

{
  "data": {
    "pet": {
      "__typename": "Dog",
      "id": "1",
      "name": "Jane"
    }
  }
}

since we have a Dog instance with key '1' in pets .

On the other hand, if we make a query for Pet with ID 2 as follows:

{
  pet(id: "2"){
    __typename,
    ...on Dog {
      id
      name
    }
    ...on Cat {
      id
      name
      age
    }
  }
}

We get:

{
  "data": {
    "pet": {
      "__typename": "Cat",
      "id": "1",
      "name": "Jane",
      "age": 11
    }
  }
}

since we have a Cat instance as the object with key '2' in pets .

Conclusion

We can create types with GraphQLObjectType constructor to create object types.

To create union types, we can use the GraphQLUnionType , then we have to resolve the type in the resolveType method by checking the type of the object and returning the right one.

We can query union types with inline fragments and check the type with __typename .

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.