# Planetscale DB and NextAuth.js starter for full stack applications

# 😃Hello !
The world is already full of news and chaos and we rarely found joyful news, then it is better to reflect back on the joyful and funny memories and experience. What is better than sharing the funny incidents and laughter with the world and make this a better place to live in. Read and share your funny incidents, and experiences on [funny-incidents](https://funny-incidents.vercel.app)⛷️⛷️⛷️

You can checkout this app and contribute fun and joy to the world or just enjoy some entries. [HostedLink](https://nextjs-planetscale-nextauth-starter.vercel.app/) and [RepoLink](https://github.com/agrittiwari/nextjs-planetscale-nextAuth-starter)

With the growing popularity of [PlanetScale](https://app.planetscale.com/) database, and my love for [NextJS]() and [Next-Auth.js](https://github.com/nextauthjs), I am more than motivated to build a full fledged appplication starter project with planetscale DB and nextauth as my tech stack. 

# 🎯Focus
>We are focusing to building a starter project with nextAuth integration to Planetscale database. We added the concept of funny incidents as an example of what can be made out of this starter. Now this starter takes care of Auth with smooth developer experience we had with Planetscale db. The standard aspects of any project is covered with this starter stack , i.e. **NextJS, NextAuth and Planetscale DB**
<iframe src="https://giphy.com/embed/TDdExacavCVvq" width="480" height="480" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/art-motion-arte-TDdExacavCVvq">via GIPHY</a></p>


# 💎Usage
You can for the [repo](https://www.github.com/agrittiwari/nextjs-planetscale-nextAuth-starter) and make your full fledged applications

# 🎒 Pre-requisites
It is an advance tutorial and expect you to have basic knowledge about some concepts, launguage and tech stack, like;
* Javascript
* CSS
* NodeJS ( [install](https://nodejs.org/en/download/))
* NextJS
* PlanetScale ([install from here](https://github.com/planetscale/cli))
* SQL database
* Basics of authZ and authN

# 🛠️ Setup
To begin setting up the project, open a folder to directory you like in the editor and console.
Write the following command to setup the project 
```
npx create-next-app projectName
```

After moving to project directory `cd projectName` , install these packages via CLI 
```
npm install next-auth @prisma/client @next-auth/prisma-adapter
npm install -g prisma
```

# Setting up NextAuth 👤and PlanetScale with Prisma

## PlanetScale🧰
As I am a windows user and wanted to experience `Planetscale CLI`, I had to install `scoop` to run planetscale cli. Follow [here](https://github.com/ScoopInstaller/Install/blob/master/README.md).

-  Set up the [PlanetScale Account](https://auth.planetscale.com/sign-up)🧰 and can create a new database from PlanetScale Dashboard

![create-database.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658557403598/7YjbQq6lr.png align="left")
 Follow up on `PlanetScale CLI` usage [here](https://docs.planetscale.com/docs/tutorials/planetscale-quick-start-guide#sign-in-to-your-account) 

### Generate a connection string
<iframe src="https://giphy.com/embed/6AnNiWdAWRkFrYWg0O" width="480" height="320" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/6AnNiWdAWRkFrYWg0O">via GIPHY</a></p>
In your PlanetScale dashboard, select your database, click "Connect", and select "Node.js" from the "Connect with" dropdown.

Copy the `DATABASE_URL` string from the `.env` tab and paste it into your own `.env `file. The structure will look like this:

```
DATABASE_URL='mysql://<USERNAME>:<PASSWORD>@<HOST>/<DATABASE_NAME>?ssl={"rejectUnauthorized":true}'
``` 

> NextAuth is an open-source library that provides authentication authorisation support. It provides various providers like `google`,`facebook`, `apple`, `discord`, etc for auth and
many adapters are integrated like `Firebase`,`MongoDB`,`FaunaDB`,`DynamoDB`,`Prisma`,etc.

> NextAuth provides hooks like `useSession`  to be used at component and page level. It is very simple to integrate functionality like login and logout as NextAuth takes care all of the functionality related to jwt, refreshToken and accessToken.

## NextAuth 🔐
To be able to use `useSession` first you'll need to expose the session context, `<SessionProvider />`, at the top level of your application:
```
pages/_app.js
----------
import '../styles/globals.css';

import { SessionProvider } from "next-auth/react"
export default function App({
  Component,
  pageProps: { session, ...pageProps },
}) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}
```
Create a file called `[...nextauth].js` in `pages/api/auth`.  And write the following code:
```
import NextAuth from "next-auth"
import GoogleProvider from 'next-auth/providers/google'
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import prisma from '../../../lib/prisma'

export default NextAuth({
  adapter: PrismaAdapter(prisma),
  // Configure one or more authentication providers
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_cLIENT_SECRET,
    }),
    // ...add more providers here
  ],
})
```
As you can clearly see, the provider used is `Google`, so you need CLIENT_ID and CLIENT_SECRET, which you can retreive from [here](https://console.cloud.google.com/). You can follow [this](https://www.youtube.com/watch?v=xH6hAW3EqLk&ab_channel=CodeJava) guide to obtain credentials and paste them in `/.env` file under root project directory.


![console google.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658493708331/0Veq4KyKj.png align="left")

## Connecting Prisma to PlanetScale and designing Schema for NextAuth
<iframe src="https://giphy.com/embed/UIUaD8DbQm2NIFU771" width="480" height="259" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/clashroyale-goblin-clash-royale-supercell-UIUaD8DbQm2NIFU771">via GIPHY</a></p>

Create a file `prisma.js` under `/lib` folder in root directory and paste the following code:
```
import { PrismaClient } from '@prisma/client';

let prisma;

if (process.env.NODE_ENV === 'production') {
  prisma = new PrismaClient();
} else {
  if (!global.prisma) {
    global.prisma = new PrismaClient();
  }
  prisma = global.prisma;
}

export default prisma;
```
> [Referenced from official docs](https://www.prisma.io/docs/guides/performance-and-optimization/connection-management#prevent-hot-reloading-from-creating-new-instances-of-prismaclient) :  Frameworks like Next.js support hot reloading of changed files, which enables you to see changes to your application without restarting. However, if the framework refreshes the module responsible for exporting PrismaClient, this can result in additional, unwanted instances of PrismaClient in a development environment.

>As a workaround, you can store PrismaClient as a global variable in development environments only, as global variables are not reloaded:

Now,  invoke prisma in your application;
```
npx prisma init 
```
This command does two things: ([referenced from here](https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases-node-planetscale))

- creates a new directory called prisma that contains a file called schema.prisma, which contains the Prisma schema with your database connection variable and schema models

- creates the .env file in the root directory of the project, which is used for defining environment variables (such as your database connection)
 

Paste the following code in file `schema.Prisma`
```
generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["referentialIntegrity"]
}

datasource db {
  provider             = "mysql"
  url                  = env("PLANETSCALE_PRISMA_DATABASE_URL")
  referentialIntegrity = "prisma"
}

model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model User {
  id            String     @id @default(cuid())
  name          String?
  email         String?    @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
  incidents     Incident[]
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

model Incident {
  id        Int      @id @default(autoincrement())
  event     String   @db.Text()
  createdAt DateTime @default(now())
  yearsAgo  Int
  country   String
  user      User?    @relation(fields: [authorId], references: [id])
  authorId  String?

  @@index([authorId])
}

```

Run the following command to generate prisma client  and re-run whenever your model changes in `schema.prisma` file
```
prisma generate
```

 
You can see the prisma client generation graphically from this image, taken from [official docs](https://www.prisma.io/docs/getting-started)

> 💡 Debug type errors for your failing model in `schema.prisma` file. You can check and update your types mapped to Prisma with respect to MySql [here](https://www.prisma.io/docs/concepts/database-connectors/mysql#native-type-mappings)

![On prisma schema change.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658556240735/9IkHOq4mp.png align="left")

## Populate the Planescale Database with updated Schema
With the database connected, you have to push the schema to your `PlanetScale Database` to perform read/write operation with Prisma client. Execute the following command:
```
npx prisma db push
```
> `prisma db push`  uses the same engine as Prisma Migrate to synchronize your Prisma schema with your database schema. The db push command:

> Introspects the database to infer and executes the changes required to make your database schema reflect the state of your Prisma schema.

> By default, after changes have been applied to the database schema, generators are triggered (for example, Prisma Client). You do not need to manually invoke prisma generate.
>[from official docs](https://www.prisma.io/docs/concepts/components/prisma-migrate/db-push)

Dashboard will be like this:

![dashboard PlanetScale 1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658579080054/Jc10yMtOa.png align="left")
![dashboard PlanetScale 2.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658579086073/RF0ftCNlC.png align="left")
### Use Prisma Client to send queries to your PlanetScale database

Prisma client is used on the server side not browser side, so the following code takes care of `GET` and `POST` requests method on the file `/api/addIncident/index.js`
```
import prisma from "../../../lib/prisma";

export default async function handler(req, res) {
  if (req.method === "POST") {
    try {
      return await addIncident(req, res);
    } catch (err) {
      console.error(err);
      return res.status(500).json({ msg: "Something went wrong" });
    }
  } else if (req.method === "GET") {
    try {
      return await getIncident(req, res);
    } catch (err) {
      console.error(err);
      return res.status(500).json({ msg: "Something went wrong" });
    }
  } else {
    return res.status(405).json({ msg: "Method not allowed" });
  }
}

//-------GET THE INCIDENTS DATA FROM DB-------//
const getIncident = async (req, res) => {
  try {
    const incidents = await prisma.incident.findMany({
      include: {
        user: true,
      },
    });
    return res
      .status(200)
      .json({ incidents, success: "Successfully get the data" });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ msg: "Something went wrong" });
  }
};

//--------ADD DATA TO TH DB OF INCIDENTS DETAILS--------//
const addIncident = async (req, res) => {
  try {
    const { event, yearsAgo, country, authorId } = req.body;
    const incident = await prisma.incident.create({
      data: {
        event,
        yearsAgo,
        country,
        authorId,
      },
    });
    return res
      .status(200)
      .json({ incident, msg: "Incident added succesfully" });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ msg: "Something went wrong" });
  }
};

```
# Why PlanetScale💻
I didn't knew MySQL database prior to this hackathon, but Planetscale has the best learning dashboard for a cloud db
* Smooth Developer experience
* Room for error and debugging with it branching capabilities
* Console at dashboard, I wrote many queries there and it's smooth
* Schema UI , simply awesome.
I am very interested in learning and building apps with relational database, because of Planetscale DB.🥳🥳
<iframe src="https://giphy.com/embed/SGZcrHnUMbl7WPJFMV" width="480" height="479" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/cbs-kids-say-the-darndest-things-darnedest-season-2-SGZcrHnUMbl7WPJFMV">via GIPHY</a></p> 

## Important Links
 ### UI code
     
You can trace the UI code from the following link and visualise the UI as well:
* [Github Link]()
* [Funny-incidents/Planetscale-nextauth-starter](https://nextjs-planetscale-nextauth-starter.vercel.app/)



#  🧑‍🚀Deployment to Vercel
To put the app in production, there are few thngs to take care of, these are:
> Do add all the domains from your vercel dashboards on [https://console.cloud.google.com/](https://console.cloud.google.com/) to use nextAuth in production with Google as provider.

![nextAuth.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658819953265/gc-knCBwj.png align="left")


## Add the environment variables
Add the following environvent variables, `NEXTAUTH_SECRET`,`GOOGLE_CLIENT_SECRET`,`GOOGLE_CLIENT_ID`, and `PLANETSCALE_PRISMA_DATABASE_URL` on the [Vercel](https://www.vercel.com) project Dashboard
![vercel environment variables.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658819246920/HIM3jmLms.png align="left")


# 🌼 Conclusion
This project can act as a starter for nextAuth and Planetscale integration. The project itself is a happy place. Thank you for your time. 

<iframe src="https://giphy.com/embed/26FPOogenQv5eOZHO" width="480" height="346" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/larrysprings-26FPOogenQv5eOZHO">via GIPHY</a></p>









