2020 Tech Stack: GraphQL Apollo server with React.js

Wojciech Cichoradzki

May 12, 20207 min read

2020 Tech Stack: GraphQL Apollo server with React.js

Table of Content

  • GraphQL vs Rest

  • GraphQL

  • Apollo GraphQL 

  • React.js

  • Our verdict 

Since 2000, RESTful principles have been the industry standard for building web APIs. While REST solved many problems that previous protocols could not, it has flaws. In modern applications, the data interconnects in complex relations which can create performance issues in product development. This is exactly what GraphQL aims at solving.

GraphQL vs Rest

Based on HTTP, REST is an easy way to communicate between the client application and the server. Data is accessible and modifiable via HTTP methods on specific endpoints. The application is thus decoupled from the server. Custom libraries are also no longer needed. The integration with different platforms is easier. 

In a news website, each article has its title, text content, date, author, and some visual content like images or videos. It may also have user’s comments grouped into threads and links to other related stories. The growing complexity in the data relationship graph shows the limits of the traditional REST approach. Each resource has to be accessed separately, often in sequence since one resource is dependable on the other. GraphQL improves the performance.


In 2015, Facebook engineers introduced GraphQL as a brand-new solution for designing APIs. The core concept of GraphQL is to give the developers more granular control over the resources needed by providing a single ‘smart’ endpoint instead of having a number of different endpoints for each resource. 

The building of GraphQL APIs is organized in terms of types and fields, not endpoints. Data retrieval methods are queries and any manipulation on the data is a mutation in GraphQL terminology. Since the demand in the industry for a solution like GraphQL was already high, it quickly gained popularity and support from developers. 

GraphQL has become popular and offers implementations in all popular programming languages. It has already been adopted by large companies like Twitter, Yelp, The New York Times, Airbnb, and more.

The developers appreciate the robustness and ease of using GraphQL. The 2019 developer survey “State of Javascript” showed that almost 40% of Javascript developers had already tried GraphQL and would use it again. The trend is rising, and we will see more GraphQL adoption in the upcoming years.

Apollo GraphQL 

Apollo is a leading GraphQL implementation that provides a set of tools and libraries that help developers build GraphQL applications. The typical Apollo server consists of a set of GraphQL schema definitions and their resolvers. To showcase the capabilities of the GraphQL, we will be building a simple application that encompasses the Apollo Node.js server and React.js client.

The application will be storing user’s read book reviews. Let’s start by creating the basic structure for the project and build our server.

$ mkdir app app/server app/client && cd app/server
$ yarn init

Next, we have to create a database with two tables: Authors and Books.

CREATE TABLE `authors` (
  PRIMARY KEY (`id`)
CREATE TABLE `books` (
  `author` INT NOT NULL,
  `title` VARCHAR(512) NOT NULL,
  `image` VARCHAR(512) NOT NULL,
  `review` VARCHAR(2048) NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`author`)
    REFERENCES `authors`(`id`)

To communicate with the database, we will be using the knex query builder library. Let’s install the required dependencies and set up a basic server.

$ yarn add dotenv knex mysql2 apollo-server
$ touch index.js

Within index.js, we are going to create our schema definitions and resolvers. We will be using two types: Author and Book. Besides, our API will expose two queries for each type, as well as a single mutation that adds a new book.

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

const knex = require('knex')({
  client: 'mysql2',
  connection: {
    host: process.env.DB_HOST || 'localhost',
    user: process.env.DB_USER || 'root',
    password: process.env.DB_PASSWORD || '1234',
    database: process.env.DB_NAME || 'books_database',

// The GraphQL schema
const typeDefs = gql`
  type Author {
    id: Int!
    name: String!

  type Book {
    id: Int!
    author: Author!
    title: String!
    image: String!
    review: String!

  type Query {
    books: [Book!]
    authors: [Author!]

  type Mutation {
    addBook(author: String!, title: String!, image: String!, review: String!): Book!

// A map of functions which return data for the schema.
const resolvers = {
  Query: {
    books: async (parent, args, context, resolveInfo) => {
      const result = await knex('books')
        .leftJoin('authors', 'books.author', 'authors.id')
        .options({ nestTables: true });
        return result.map(({ books, authors }) => ({
        author: authors,
    authors: async () => knex('authors').select('*'),
  Mutation: {
    addBook: async (parent, {
      author: authorName, title, image, review,
    }) => {
      let author = await knex('authors').first().where({ name: authorName });
      if (!author) {
        const [authorId] = await knex('authors').insert({ name: authorName });
        author = {
          id: authorId,
          name: authorName,
      const newBook = {
        author: author.id,
      const [bookId] = await knex('books').insert(newBook);
      return {
        id: bookId,

const server = new ApolloServer({

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);

Now, to start the server and test our API with the knex logs exposed, we have to run Node.js on our index.js file:

DEBUG=knex:query node index.js 🚀 Server ready at http://localhost:4000/

Next, if we open http://localhost:4000/, we are welcomed by what is called GraphQL playground. Here, we can easily test our API. 

Let's attempt to retrieve all the books using the following command in the GraphQL playground: 

query { books { title author } } 

At this stage, you should see an empty array as a response, indicating that there are currently no books.

Since we currently don’t have any book stored, the response is just an empty array. 

We can add books by executing the addBook mutation. For example, you can use the following command in the GraphQL playground: 

mutation { addBook(title: "New Book", author: "John Doe") { title author } } 

This will return the added book's title and author in the response.

When we query books again using the same command as before: 

query { books { title author } }

 we should see the newly created book in the response list.

 Our "books" resolver is performing a left join on the ‘authors’ table to retrieve the id and name of the author and pass it to the response. However, when the author field is not requested, the expensive left join operation could be omitted. To achieve such optimization, we can use the graphql-parse-resolve-info package and refactor our resolver, so it checks whether the author field is present in the request.

const {
} = require('graphql-parse-resolve-info');
    books: async (parent, args, context, resolveInfo) => {
      const query = knex('books')
        .options({ nestTables: true });
      const simplifiedFragment = simplifyParsedResolveInfoFragmentWithType(
      if (simplifiedFragment.fields.author) {
        query.leftJoin('authors', 'books.author', 'authors.id');
      const result = await query;
      return result.map(({ books, authors: author }) => ({

If we modify the query by removing the author field, like so: 

query { books { title } }

we would observe a change in the SQL queries performed. This is because the query has become more specific and now only requests the titles of the books.

Our API is now ready to be used by our client application.


We initialize the React project by using create-react-app and installing the required dependencies:

cd .. && npx create-react-app client && cd client yarn add apollo-boost @apollo/react-hooks graphql

Now, when running yarn start, a basic starter project should open. Let’s create our GraphQL client and expose it to the sub-components via a context provider. We need to modify index.js like this:

import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloProvider } from '@apollo/react-hooks';
import ApolloClient from 'apollo-boost';

import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

const client = new ApolloClient({
  uri: 'http://localhost:4000',

    <ApolloProvider client={client}>
      <App />

As a consequence, we need to perform a query to our API and render a list of books. Apollo gives a set of useful React hooks that help us do that. In our case, we will use the useQuery hook with our previously used GraphQL books query attached. Let’s modify our App.js so it fetches and renders the stored books.

import React from 'react';
import { useQuery } from '@apollo/react-hooks';
import { gql } from 'apollo-boost';

const BOOK_QUERY = gql`

export default function App() {
  const { loading, error, data } = useQuery(BOOK_QUERY);

  if (loading) {
    return <p>Loading...</p>;
  if (error) {
    return <p>Error :(</p>;

  return (
    <div className="App">
      <h2>My Books</h2>
      { data.books.map(({ id, author, title, image, review }) => (
      <div key={id}>
        <img src={image} alt={title} />
        <p>{ title }</p>
        <p>{ author.name }</p>
        <p>{ review }</p>

Now, after the refresh, our app successfully renders a list of books. However, the styling is not too appealing. Let’s add the milligram.css library, extract the Book component to a separate module, and add a bit of CSS magic.


<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/milligram/1.3.0/milligram.css">


export default function Book({ author, title, image, review }: Props) {
  return (
    <div className="book container">
      <div className="row">
        <div className="column-10">
            alt="book cover"
        <div className="column-90">
          <h4 className="title">{ title }</h4>
          <i>{ author }</i>
          <p>{ review }</p>


.App {
  margin: 2rem 20%;

.book .cover {
  width: 100px;
  height: auto;
  margin-right: 2rem;

.book .title {
  margin-bottom: 0;
  font-weight: bold;

After these adjustments and improvements to our GraphQL queries, our data fetching capabilities are more efficient and our application is more responsive.

highlightOur verdict 

The simplicity and robustness of GraphQL, especially when combined with Apollo and React, is the best to use in an all-purpose 2020 tech stack. In the coming months, we expect to see a wider adoption and further optimizations by the growing community. Interested in learning more? Check out our blog for more articles on development tools.

Do you have any questions about product development? If so, head to our contact page or drop us a line at

Don't miss a beat - subscribe to our newsletter
I agree to receive marketing communication from Startup House. Click for the details

Published on May 12, 2020


Wojciech Cichoradzki JavaScript Developer

You may also highlightlike...

Flask vs Django: Which Python Web Framework to Use?
PythonDigital productsProduct development

Flask vs Django: Which Python Web Framework to Use?

Python is a popular programming language extensively used in web development, machine learning, and various other technology sectors. Two of the popular Python-based frameworks that have gained substantial recognition in the web development industry are Flask and Django. These frameworks, Flask and Django, have their unique strengths, and the choice between "Flask v Django" or "Django vs Flask" often boils down to the specific needs of the project.

Marek Majdak

Jul 04, 20238 min read

Product Owner vs Project Manager - Understanding Key Roles in Your Organization
Project managementProduct managementProduct development

Product Owner vs Project Manager - Understanding Key Roles in Your Organization

The product owner is deeply involved with the product and its potential users, while the project manager oversees the project execution with an emphasis on timelines, resource allocation, and project scope.

Damian Czerw

Feb 07, 20235 min read

Lean Development Methodology: Principles, Benefits, and Implementation
Project managementProduct development

Lean Development Methodology: Principles, Benefits, and Implementation

In today's rapidly evolving software development landscape, companies are constantly seeking ways to optimize their processes and efficiently deliver high-quality products. One approach that has gained significant traction is Lean Development Methodology. This article aims to explore the principles, benefits, and implementation of Lean Development, shedding light on agile methodology and how it can revolutionize software development practices.

Marek Pałys

Feb 07, 20235 min read

Let's talk
let's talk

Let's build

something together


We highlightbuild startups from scratch.

Startup Development House sp. z o.o.

Aleje Jerozolimskie 81

Warsaw, 02-001

VAT-ID: PL5213739631

KRS: 0000624654

REGON: 364787848

Contact us

Follow us


Copyright © 2023 Startup Development House sp. z o.o.

EU ProjectsPrivacy policy