Stacking Vercel, a GraphQL Apollo Server and React

Jan 14, 2021 17:11 · 932 words · 5 minute read GraphQL React Vercel Apollo Server JavaScript

Introduction

Vercel makes it seamless to deploy React single page applications. Given its use of serverless functions however, hosting a GraphQL API using Apollo Server on Vercel is less straightforward. This worked example for Linux demonstrates how it might be done - borrowing code from my earlier Oh-so minimal GraphQL API example with Apollo Server tutorial.

All code can be found on github at my vercel-apollo-server-react repo. The end result of the demo is also hosted on Vercel at vercel-apollo-server-react.preciouschicken.vercel.app.

Create-React-App

To get us started:

npx create-react-app vercel-apollo-server-react
cd vercel-apollo-server-react
npm i apollo-server-micro @apollo/client

GraphQL Server

Vercel expects serverless functions to be located in a folder named api, so create this first:

mkdir api

Within this folder three files are needed: some data for the server to play with, a schema explaining how the data is structured and an instance of Apollo Server itself.

The data

As this is a demonstration only, we are going to use a JSON file to act as our datastore (as for data content - I’m taking inspiration from There Was an Old Lady Who Swallowed a Fly). Create the file api/db.json and paste the following:

{
  "beasts": [
    {
	    "id": "md",
	    "legs": 6,
	    "binomial": "Musca domestica",
	    "commonName": "housefly"
    },
    {
	    "id": "nr",
	    "legs": 8,
	    "binomial": "Neriene radiata",
	    "commonName": "filmy dome spider"
    },
    {
	    "id": "cc",
	    "legs": 2,
	    "binomial": "Corvus corone",
	    "commonName": "carrion crow"
    },
    {
	    "id": "fc",
	    "legs": 4,
	    "binomial": "Felis catus",
	    "commonName": "cat"
    }
  ]
}

The schema

Create api/schema.js and paste the following very basic schema (for a more full-fat schema see my previous tutorial):

import { gql } from 'apollo-server-micro';
import db from './db.json';

// The statements within quotes are used by GraphQL to provide
// human readable descriptions to developers using the API
export const typeDefs = gql`
	type Beast {
		"ID of beast (taken from binomial initial)"
		id: ID
		"number of legs beast has"
		legs: Int
		"a beast's name in Latin"
		binomial: String
		"a beast's name to you and I"
		commonName: String
	}

	type Query {
		beasts: [Beast]
	}
`
export const resolvers = {
	Query: {
		// Returns array of all beasts.
		beasts: () => db.beasts,
	}
}

Apollo Server

The serverless function that instantiates Apollo Server itself should be pasted in api/graphql.js as:

import { ApolloServer, makeExecutableSchema } from 'apollo-server-micro'
import { typeDefs, resolvers  } from './schema';

export default new ApolloServer({
    typeDefs,
    resolvers,
    introspection: true,
    playground: true,
}).createHandler({
    path: '/api/graphql',
})

The introspection and playground variables are normally excluded in production, but leaving them in means the GraphQL playground is still accessible.

Front end

API complete, we now need to edit the React elements within the src folder. Delete the contents of src/index.js and replace with:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { createHttpLink, ApolloProvider, ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: createHttpLink({ uri: "/api/graphql" }),
});

ReactDOM.render(
  <React.StrictMode>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

Finally delete the contents of src/App.js, replacing with:

import React from 'react';
import { gql, useQuery } from '@apollo/client';
import './App.css';

function App() {

  const GET_BEASTS = gql`
  query {
    beasts {
      id
      commonName
      legs
      binomial
    }
  }`;

  const { loading, error, data } = useQuery(GET_BEASTS);
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error</p>;
  return (
    <div className="App">
      <header className="App-header">
        <h1>Stacking Vercel, a GraphQL Apollo Server and React</h1>
        <p>A table of animals eaten by an old woman:</p>
        <table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Legs</th>
              <th>Binomial</th>
            </tr>
          </thead>
          <tbody>
            {data.beasts.map(beast => 
            <tr key={beast.id}>
              <td>{beast.commonName}</td>
              <td>{beast.legs}</td>
              <td>{beast.binomial}</td>
            </tr>
            )}
          </tbody>
        </table>
        <small>
          <p>This is a demo page to accompany the tutorial <br/>
            <a className="App-link"
              href="https://www.preciouschicken.com/blog/posts/vercel-apollo-server-react">
              preciouschicken.com/blog/posts/vercel-apollo-server-react
            </a></p>
          <p>Consult your own physicican before eating any of the animals on this table.</p>
        </small>
      </header>
    </div>
  );
}

export default App;

Upload to Vercel

There are a number of ways to upload to Vercel, I typically use the Github repo integration, but for the purposes of this walk though we’ll use the CLI option. This of course assumes you have already signed up with Vercel. Ensuring you are in the root directory login:

npx vercel login

At this point you will have to enter the address used to sign up to Vercel, a confirmation email will be sent and once verified it will confirm in the terminal. Once done we upload:

npx vercel --prod

Accept all of the default options and, once uploaded, Vercel will confirm it has built correctly and will provide your application’s URL. Following the link, if all has gone well, should take you to a page that looks like:

Vercel demo screenshot

The above live version can be viewed on Vercel at vercel-apollo-server-react.preciouschicken.vercel.app.

It’s worth noting that if you want to spin this up on your local machine for development purposes, without uploading to the web, then running npm start will not work due to the serverless function. Instead use:

npx vercel dev

Conclusion

If you have found this useful or have feedback, please do leave a comment below. Some other resources I have produced on GraphQL are:

Version control

This example uses Vercel CLI 21.1.0, node v15.2.0, npm v6.14.11, @apollo/client v3.3.6, apollo-server-micro v2.19.1 and Ubuntu 20.04.1 (Regolith flavour). If following the instructions does not work first time then this might be the problem - try cloning the repo to start with and running npm i && npx vercel dev (assuming you have a Vercel logon).

tweet Buy Me a Coffee at ko-fi.com
₿⚡ Or buy me a coffee with Bitcoin Lightning