DEV Community

Cover image for Apollo GraphQL: How to build a Full-stack app with React and Node Js
Ibrahima Ndaw
Ibrahima Ndaw

Posted on • Originally published at ibrahima-ndaw.com

Apollo GraphQL: How to build a Full-stack app with React and Node Js

Apollo Client is a complete state management library for JavaScript apps. It's a powerful tool since it can be used on both back-end and front-end side.
In this tutorial, we will use it on both by building first an Apollo GraphQL Server with Node JS and then consume the data on the client-side using React JS.

If you're new to GraphQl, this tutorial might help you. Otherwise, Let's get started.

Originally posted on my blog

Building the server with Apollo, Node, and GraphQl

In this guide, I will use the Github API to have data to show, and that operation will be done by the GraphQl server built with Apollo and Node JS.
And to do so, we need to run the following command on the terminal to set up a new Node JS project.

  yarn init
Enter fullscreen mode Exit fullscreen mode

Once the set up is done, we can now install the needed packages by running this command.

  yarn add apollo-server graphql axios
Enter fullscreen mode Exit fullscreen mode

Great, we have now all we need to build a server, let's create first a new file app.js in the root which will be the entry point of our server.

Next, we need to define a Graphql schema that mirrors the way our data should look like.

GraphQl Schema

A schema describes the shape of your data graph. It defines a set of types with fields that are populated from your back-end data stores. So, let's add a new schema in the app.js file.

  • app.js
const { ApolloServer, gql } = require("apollo-server")
const axios = require("axios")

const typeDefs = gql`
  type User {
    id: ID
    login: String
    avatar_url: String
  }

  type Query {
    users: [User]
  }
`
Enter fullscreen mode Exit fullscreen mode

As you can see we don't use all data provided by the Github API. We just need the id that will be used as a reference key on the React App, the login, and the avatar_url. We also have a query users that returns an array of users.

Now we have a GraphQL schema, it's time to build the corresponding resolvers to complete the query operation.

GraphQl resolvers

A resolver is a collection of functions that helps generating a response from a GraphQL query. So, let's add a new resolver in the app.js file.

  • app.js
const resolvers = {
  Query: {
    users: async () => {
      try {
        const users = await axios.get("https://api.github.com/users")
        return users.data.map(({ id, login, avatar_url }) => ({
          id,
          login,
          avatar_url,
        }))
      } catch (error) {
        throw error
      }
    },
  },
}
Enter fullscreen mode Exit fullscreen mode

A resolver has to match by name the appropriate schema. Therefore, here users refers to the users query defined in our schema. It's a function that fetches the data from the API with the help of axios and returns as expected the id, the login, and the avatar_url.
And that operation can take time to complete that's why async/await is used here to handle it consequently.

With that, we can now create the Apollo Server in the next section.

Creating the Apollo Server

If you remember, in the app.js file, we had imported ApolloServer from the apollo-server package, it a constructor that receives an object as an argument. And that object must contain the schema and the resolver to be able to create the server.

So, let's tweak app.js a bit with ApolloServer.

  • app.js
const server = new ApolloServer({
  typeDefs,
  resolvers,
})
//  typeDefs: typeDefs,
//  resolvers: resolvers
server.listen().then(({ url }) => console.log(`Server ready at ${url}`))
Enter fullscreen mode Exit fullscreen mode

Here, we pass as a parameter an object that holds the schema and the resolver to ApolloServer to create the server and then listens to it. With that in place, we have now a functional server to work with.

You can already play with it and send queries with the help of GraphQL playground by running this command:

  yarn start
Enter fullscreen mode Exit fullscreen mode

You can now preview it on http://localhost:400

  • The complete app.js file
const { ApolloServer, gql } = require("apollo-server")
const axios = require("axios")

const typeDefs = gql`
  type User {
    id: ID
    login: String
    avatar_url: String
  }

  type Query {
    users: [User]
  }
`

const resolvers = {
  Query: {
    users: async () => {
      try {
        const users = await axios.get("https://api.github.com/users")
        return users.data.map(({ id, login, avatar_url }) => ({
          id,
          login,
          avatar_url,
        }))
      } catch (error) {
        throw error
      }
    },
  },
}

const server = new ApolloServer({
  typeDefs,
  resolvers,
})

server.listen().then(({ url }) => console.log(`Server ready at ${url}`))
Enter fullscreen mode Exit fullscreen mode

A server alone does not do much, we need to add a start script in the package.json file to as you guessed start the server.

  • package.json
  // first add nodemon: yarn add nodemon --dev
  "scripts": {
    "start": "nodemon src/index.js"
  }
Enter fullscreen mode Exit fullscreen mode

With that, we have now a server to fetch data from the Github API, it's time to move to the client-side and consume the data.

Let's do it

yaay

Building the Client-side with React

The first thing we have to do is creating a fresh React App by running in the terminal the following command

npx create-react-app client-react-apollo
Enter fullscreen mode Exit fullscreen mode

Next, we need to install the Apollo and GraphQl packages.

  yarn add apollo-boost @apollo/react-hooks graphql
Enter fullscreen mode Exit fullscreen mode

Now, we can connect Apollo with our React App by updating the index.js file.

Connecting React to Apollo

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

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

const client = new ApolloClient({
  uri: 'https://7sgx4.sse.codesandbox.io'
})


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

serviceWorker.unregister();
Enter fullscreen mode Exit fullscreen mode

As you can see, we start by importing ApolloClient and ApolloProvider. The first helps us to inform Apollo about the URL to use when fetching data. And if no uri is passed to ApolloClient, it will take the current domain name plus /graphql.
The second is the Provider which expects to receive the client object to be able to connect Apollo to React.

That said, we can now create a component that shows the data.

Fetching the data

  • App.js
import React from "react"
import { useQuery } from "@apollo/react-hooks"
import gql from "graphql-tag"
import "./App.css"

const GET_USERS = gql`
  {
    users {
      id
      login
      avatar_url
    }
  }
`
Enter fullscreen mode Exit fullscreen mode

Here, we have a simple GraphQL query that fetches the data. That query will be passed later to useQuery to tell to Apollo which data to fetch.

  • App.js
const User = ({ user: { login, avatar_url } }) => (
  <div className="Card">
    <div>
      <img alt="avatar" className="Card--avatar" src={avatar_url} />
      <h1 className="Card--name">{login}</h1>
    </div>
    <a href={`https://github.com/${login}`} className="Card--link">
      See profile
    </a>
  </div>
)
Enter fullscreen mode Exit fullscreen mode

This presentational component will be used to display a user. It receives the data from the App component and displays it.

Showing the data

  • App.js
function App() {
  const { loading, error, data } = useQuery(GET_USERS)

  if (error) return <h1>Something went wrong!</h1>
  if (loading) return <h1>Loading...</h1>

  return (
    <main className="App">
      <h1>Github | Users</h1>
      {data.users.map(user => (
        <User key={user.id} user={user} />
      ))}
    </main>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

The useQuery hook provided by Apollo receives the GraphQL query and returns three states: the loading, the error, and the data.
If the data are successfully fetched, we pass it to the User component otherwise we throw an error.

  • The complete App.js file
import React from "react"
import { useQuery } from "@apollo/react-hooks"
import gql from "graphql-tag"
import "./App.css"

const GET_USERS = gql`
  {
    users {
      id
      login
      avatar_url
    }
  }
`

const User = ({ user: { login, avatar_url } }) => (
  <div className="Card">
    <div>
      <img alt="avatar" className="Card--avatar" src={avatar_url} />
      <h1 className="Card--name">{login}</h1>
    </div>
    <a href={`https://github.com/${login}`} className="Card--link">
      See profile
    </a>
  </div>
)

function App() {
  const { loading, error, data } = useQuery(GET_USERS)

  if (error) return <h1>Something went wrong!</h1>
  if (loading) return <h1>Loading...</h1>

  return (
    <main className="App">
      <h1>Github | Users</h1>
      {data.users.map(user => (
        <User key={user.id} user={user} />
      ))}
    </main>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Great! with that, we have now done building a full-stack Apollo GraphQL app using React and Node JS.

Preview the Apollo GraphQL Server here

Preview the React App here

Find the source code here

Thanks for reading

congrats

Top comments (12)

Collapse
 
seanmclem profile image
Seanmclem

Does graphql not require you to host your database somewhere? Most guides don't seem to mention it and I can't find the answer

Collapse
 
ibrahima92 profile image
Ibrahima Ndaw

No, GraphQl does not care about which DB you're using. It's just a query language, and it's your job to define the way you want to interact with the DB. To conclude, you can use whatever you like as DB.

Collapse
 
therealdakotal profile image
Dakota Lewallen

Yes it does, if you would like to see how to do that, I have a guide I've written. dev.to/fastflowz/generate-graphql-...

Collapse
 
romidevx profile image
romidevx

Hey thankx for sharing this tutorial....but im trying to understand where that param "url" inside the app.js "server.listen().then(({url})" line of code came from ? And the script in the package.json "nodemon src/index.js...cuz i dont see the file " index.js ?

Collapse
 
vinodnlee profile image
Vinod Nagaraj

Hi Could you please let me know if you are using Appollo2.0 here

Collapse
 
ibrahima92 profile image
Ibrahima Ndaw

Yes, it's version 2 on the server and Apollo v3 on the client-side.

Collapse
 
sm0ke profile image
Sm0ke

This is super nice. Thanks!

Collapse
 
ibrahima92 profile image
Ibrahima Ndaw

Thanks for reading

Collapse
 
xarala221 profile image
Ousseynou Diop

Super interesting.
Keep it up.

Collapse
 
ibrahima92 profile image
Ibrahima Ndaw

Thanks bud