Skip to content

Deploy a fullstack web app with cutting-edge tooling in 60 seconds.

Notifications You must be signed in to change notification settings

kunalgorithm/graphql-fullstack

Repository files navigation

GraphQL Fullstack Boilerplate

A monorepo web application boilerplate with a graphQL API, server-side cookie authentication with bcrypt and jwt, database access with Prisma 2, and styling with Ant Design.

Demo GIF

But Why

When building a new project, choosing a technology stack, configuring it, wiring it all together, and figuring out how to dpeloy it properly tends to take far more time that building and shipping features (the important and enjoyable part). This boilerplate starts you off with an app that already works, so you can get right to the good stuff.

Features

⚡️ Deploy a full-featured production-ready web application in less than 60 seconds.

🔐 Allow users to sign up and log in with an email and password, view their profiles and data, and log out. Outputs feedback for loading and errors states to enhance UX.

📃 Includes a splash page, login page, sign up page, and dashboard.

🤖‍‍ Includes wired up forms, queries, mutations, snackbars, and more commonly used components.

☁️ Zero Config Deployments. It just works 🔥

Tech stack

🤖 Typescript - static types, used throughout the client and server (especially handy for the auto-generated prisma2 client).

🌚 Next.js - server-side rendering, file-based routing in the pages directory, and serverless build of of graphql API within pages/api/graphql.ts using API Routes.

🦋 Apollo (React Hooks API) - GraphQL client for queries and mutations.

🦄 Prisma - Next-generation database access and migration tools.

💅 Ant Design - Beautiful, responsive, easy-to-use components.

🚀Render - app and postgres deployment.

Quick Start

Clone the repository

git clone https://github.com/kunalgorithm/graphql-fullstack

install dependencies, then run the development server:

yarn
yarn dev

Development

Create new data types

Create a new project and install the prisma CLI, along with typescript, as development dependencies

npm init -y
yarn add -D @prisma/cli typescript ts-node @types/node

You can now invoke the prisma CLI

npx prisma

Then, open schema.prisma in the prisma directory and add the following

datasource sqlite {
  provider = "sqlite"
  url      = "file:./dev.db"
}

generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native"]
}

model User {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  email     String   @unique
  name      String?
  password String

}

Migrate your database

yarn migrate:save

and add a name, perhaps simply "init", to save your first database migration. When asked whether to create a SQLite file, select yes. Then, apply the migration by running

yarn migrate:up

Finally, run

yarn generate

to generate the prisma client to reflect the new changes.

Adding a new field

Open schema.prisma in the prisma directory. Add a new optional field, githubUrl to a data type, User.

model User {
  id         Int      @id @default(autoincrement())
  createdAt  DateTime @default(now())
  email      String   @unique
  name       String?
  password   String
  githubUrl  String?
}

Note: the ? signals that the field is optional.

Make it available to the frontend.

Now that you've added a new field to your database and made it available to the server, you need to make it available to your client by defining it within the graphQL endpoint's type definitions.

Open the API type defintion file at apollo/typedefs.js and extend

type User {
  id: ID!
  email: String!
  name: String
  password: String!
  posts: [Post!]!
+ graphqlUrl: String
}

Now, render the new data on the app by adding it to the query on the Profile component

const { loading, error, data, client } = useQuery(
  gql`
    query {
      me {
        id
        name
        email
+       githubUrl
      }
    }
  `
);

Now, you'll have the data.me.githubUrl available to you (with typesafety and auto-completion!) in your react components ✨

NOTE: If you aren't seeing the new field, you may have forgotten to run yarn migrate to update the prisma client after migrating the database.

Authentication

The API sets a server-side cookie with http: only enabled on the root of the domain, seen in the login and signup resolvers:

ctx.res.setHeader(
  "Set-Cookie",
  cookie.serialize("token", token, {
    httpOnly: true,
    maxAge: 6 * 60 * 60, // 6 hours
    path: "/",
    sameSite: "lax",
    secure: process.env.NODE_ENV === "production",
  })
);

which is automatically attached to subsequent requests to the server and parsed and accessible via NextJS's API Routes for resolvers that require authenticated users:

const { token } = cookie.parse(ctx.req.headers.cookie ?? "");

if (token) {
  try {
    const { id, email } = jwt.verify(token, JWT_SECRET);
    return await ctx.prisma.user.findOne({ where: { id } });
  } catch {
    throw new AuthenticationError(
      "Authentication token is invalid, please log in"
    );
  }
}

This solves two problems pervasive in modern javascript applications:

  1. The cookies cannot be read from client-side javascript, protecting the application from cross-site forgery attacks.
  2. The cookie is attached to requests received by the server automatically, allowing server-side requests from Next to be authenticated without requiring the client to handle and attach the token manually. This not only speeds up data requests, but cleans up the client-side code quite a bit.

Deployment

This app uses SQLite for local development, which stores application data in a local file. To deploy the platform, however, you'll have to provision a postgres or MySQL database in the cloud for your deployment to connect to.

You can prepare for this by switching from developing on SQLite locally to a local postgres instance. To do this, change the datasource in schema.prisma to

datasource postgres {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

and set the DATABASE_URL as an environment variable in your terminal

export DATABASE_URL=postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public

Then, follow the instructions above for Migrating your database, then restart your development server on the same terminal and ensure you can read and write data to the new database correctly.

Deploying Render

You deploy this app and a managed postgres instance on Render and connect to it securely with an internal connection string, only useable by applications on the Render platform.

Note: that web service starter plan deployments and postgres database starter instances each cost $7/month on render at the time of writing.

To deploy on render, just hit

Deploy to Render

Contributions welcome!

Feel free to open an issue or submit a pull request 🙂

Need help?

Send me a DM on twitter! @kunalgorithm