DEV Community

Cole Bemis
Cole Bemis

Posted on

Building a Full Stack App with React, TypeScript, and GraphQL

Introduction

Web development can be overwhelming. With countless libraries and frameworks out there, it can be hard to piece together technologies to build a complete full stack web application. Through trial and error, I've found a technology stack and development workflow for building web applications that works for me. Hopefully my setup will give you some ideas.

What we’ll cover

In the post, I’ll give you an overview of the libraries and frameworks I use. I’ll explain how I structure my projects and walk through my typical development workflow. My goal is to show you how all the pieces fit together.

What we won’t cover

I will not be going in-depth on any specific technology. Instead, I’ll provide links to more detailed documentation and articles where you can learn more. If you’re looking for a comprehensive deep dive on building full stack web applications with React, I recommend checking out Wes Bos’ Advanced React course.

Table of contents

Architecture

Architecture diagram

Frontend

  • React - A JavaScript library for building user interfaces
  • Next.js - A framework for building server-rendered apps with React
  • Emotion - A library designed for writing CSS styles with JavaScript
    • Styled Components is another popular choice for writing CSS styles with JavaScript.
  • Apollo Client - A GraphQL client and state management library for JavaScript apps
  • GraphQL Code Generator - Generate code from a GraphQL schema

Backend

  • Prisma - Database tools for modern application development
  • Nexus - Code-First, Type-Safe, GraphQL Schema Construction
  • GraphQL Yoga - Fully-featured GraphQL Server

Deployment

  • Now - A static hosting platform
    • I use Now to deploy my frontend and GraphQL API.
  • Heroku - A cloud application platform
    • I use Heroku to run my Prisma Server and database.

Folder structure

Here's how I structure my projects:

frontend/          # Where all the frontend code lives
  package.json     # Manifest file with a list of package dependencies for frontend
  next.config.js   # Config file for Next.js
  pages/           # Each file in this folder becomes a page with a URL based on its path
  graphql/         # GraphQL queries and mutations
  components/      # React components
  lib/             # Miscellaneous utility functions
  __generated__/   # Auto-generated React components and TypeScript types
backend/           # Where all the backend code lives
  package.json     # Manifest file with a list of package dependencies for backend
  src/            
    index.ts       # Entrypoint for the GraphQL server
    schema.ts      # Schema definition for GraphQL Server
    __generated__/ # Auto-generate TypeScript types
  prisma/          # Prisma datamodel and config files
Enter fullscreen mode Exit fullscreen mode

Note: I use Yarn Workspaces to easily manage dependencies and run scripts for both the frontend and backend.

Workflow

To illustrate my typical development workflow, let's walk through the process of adding displaying a list of posts on our application:

1. Start the development server

To start local development, we can run yarn dev from the root directory.

yarn dev
Enter fullscreen mode Exit fullscreen mode

This will run the frontend development server on localhost:3000 and the GraphQL API server on localhost:4000.

2. Update the datamodel

Next, in backend/prisma/datamodel.prisma, we need to create a Post type:

type Post {
  id: ID! @id
  createdAt: DateTime! @createdAt
  updatedAt: DateTime! @updatedAt
  author: String!
  title: String!
  content: String!
}
Enter fullscreen mode Exit fullscreen mode

This is a special language for defining datamodels in Prisma. It’s similar to how you define GraphQL schemas.

3. Deploy the datamodel changes

Before we can do anything with our new Post type, we have to deploy our changes:

prisma deploy
Enter fullscreen mode Exit fullscreen mode

This will automatically run a database migration and generate a GraphQL API that will allow us to perform CRUD options on posts. It will also generate TypeScript types that we can use in our GraphQL API.

4. Update the GraphQL API

Next, we need to update our GraphQL API to enable our frontend to display and edit posts. Since Prisma’s GraphQL API already exposes CRUD operations for posts, we can just proxy those fields. Here’s how we do that with Nexus:

const Query = prismaObjectType<'Query'>({
  name: 'Query',
  definition(t) {
    t.prismaFields([
+     'post', 
+     'posts',
    ])
  },
})

const Mutation = prismaObjectType<'Mutation'>({
  name: 'Mutation',
  definition(t) {
    t.prismaFields([
+     'createPost',
+     'updatePost',
+     'deletePost',
    ])
  }
})

Enter fullscreen mode Exit fullscreen mode

5. Write a GraphQL query

We use the frontend/graphql directory to co-locate all the queries and mutations used in the frontend. So, let’s create a file called getPosts.graphql in this directory and write a query to get a list of posts:

query getPosts {
  posts {
    id
    createdAt
    title
    content
  }
}
Enter fullscreen mode Exit fullscreen mode

6. Generate GraphQL types and components

Before we can use this query, we need to generate React components and TypeScript types for it. This is where GraphQL Code Generator comes in handy. With one command, we can generate React components and types for all .graphql files in our project:

gql-gen
Enter fullscreen mode Exit fullscreen mode

The generated output will be placed in frontend/__generated/graphql.tsx.

7. Update the frontend

In any React component, we can now import the code generated by GraphQL Code Generator and use it display a list of posts:

import { GetPostsComponent } from '../__generated__/graphql'

export default function App() {
  return (
    <GetPostsComponent>
      {({ loading, error, data }) => {
        if (loading) return <p>Loading...</p>
        if (error) return <p>Error: {error.message}</p>
        return (
          <ul>
            {data.posts.map(post => (
              <li key={post.id}>{post.title}</li>
            )}
          </ul>
        )
      }}
    </GetPostsComponent>
  )
}

Enter fullscreen mode Exit fullscreen mode

8. Deploy

We've now made all the necessary frontend and backend changes to display posts. It's time to deploy our changes. With Now, we just need to run a single command:

now
Enter fullscreen mode Exit fullscreen mode

Now will deploy the application to a unique URL (e.g. my-app-f9shcvmf1.now.sh).

Demo

If you're interested in seeing this technology stack and workflow in a real project, check out https://github.com/colebemis/dasher.

Helpful links

Top comments (2)

Collapse
 
floroz profile image
Daniele Tortora

I would consume the GraphQL API on the front end using react-apollo/hooks.

The pattern shown in this example use the render prop pattern, which was previously used by Apollo (and previous Context API) and leads to the 'component callback hell' which affects readability.

I think the apollo hooks approach (that leverages the new Context API) is much cleaner and more readable :)

Collapse
 
thompsonad profile image
Aaron Thompson

This is brilliant Cole. Thank you so much