Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tigris example with Next.js #42662

Merged
merged 7 commits into from Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/with-tigris/.env.development
@@ -0,0 +1,4 @@
# DO NOT ADD SECRETS TO THIS FILE. This is a good place for defaults.
# If you want to add secrets use `.env.development.local` instead.

TIGRIS_URI=localhost:8081
7 changes: 7 additions & 0 deletions examples/with-tigris/.env.local.example
@@ -0,0 +1,7 @@
# Enter your tigris uri, ex :- localhost:8081, api.preview.tigrisdata.cloud etc.
TIGRIS_URI=

# Client credentials, if using auth, can be generated from Tigris cloud console.
# See: https://docs.tigrisdata.com/auth
TIGRIS_CLIENT_ID=
TIGRIS_CLIENT_SECRET=
4 changes: 4 additions & 0 deletions examples/with-tigris/.env.production
@@ -0,0 +1,4 @@
# DO NOT ADD SECRETS TO THIS FILE. This is a good place for defaults.
# If you want to add secrets use `.env.production.local` instead.

TIGRIS_URI=api.preview.tigrisdata.cloud
27 changes: 27 additions & 0 deletions examples/with-tigris/.gitignore
@@ -0,0 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
171 changes: 171 additions & 0 deletions examples/with-tigris/README.md
@@ -0,0 +1,171 @@
# ⚡ ️Tigris example app on Next.js - Todo list

A simple todo app built on [Next.js][next-url] and [Tigris](https://docs.tigrisdata.com/)
using [TypeScript client](https://docs.tigrisdata.com/typescript/), deployed on [Vercel][vercel-url].

### Project demo

https://tigris-nextjs-starter-kit.vercel.app/

# ⚙️ Deploying your own

All you need is a [Github](https://github.com), [Vercel][vercel-url] and Tigris
account([sign up for a free account](https://www.tigrisdata.com/nextjs#signup-form)). Now, Hit "Deploy"
and follow instructions to deploy app to your Vercel account

[![Deploy with Vercel](https://vercel.com/button)][deploy-url]

:tada: All done. You should be able to use app on the URL provided by Vercel. Feel free to play around
or do a [code walkthrough](#code-walkthrough) next :tada:

> [Tigris integration](https://vercel.com/integrations/tigris) with Vercel will automatically fetch
> access keys to populate [Environment Variables](.env.local.example) when deploying app.

<details>
<summary>2. Running Next.js server & Tigris dev environment on your local computer</summary>

## 📖 Running Next.js server & Tigris locally

### Prerequisites

1. Tigris installed on your dev computer
1. For **macOS**: `brew install tigrisdata/tigris/tigris-cli`
2. Other operating systems: [See installation instructions here](https://docs.tigrisdata.com/cli/installation)
2. Node.js version 16+

### Instructions

1. Clone this repo on your computer

```shell
git clone https://github.com/tigrisdata/tigris-vercel-starter
```

2. Install dependencies

```shell
cd tigris-vercel-starter
npm install
```

3. Start Tigris local development environment

```shell
tigris dev start
```

4. Run the Next.js server

```shell
npm run dev
```

> Note: This step uses a custom dev & build script to initialize Tigris database and collection for
> the app and requires [ts-node](https://www.npmjs.com/package/ts-node#installation) to be installed.

:tada: All done. You should be able to use app on `localhost:3000` in browser. Feel free to play
around or do a [code walk-through](#code-walkthrough) next :tada:

</details>

# 📖 How to use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:

```bash
npx create-next-app --example with-tigris tigris-next-app
```

```bash
yarn create next-app --example with-tigris tigris-next-app
```

```bash
pnpm create next-app --example with-tigris tigris-next-app
```

Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

# 👀 Code walkthrough

<details>
<summary> 📂 File structure</summary>

```text
├── package.json
├── lib
│ ├── tigris.ts
├── models
│ └── tigris
│ └── todoStarterApp
│ └── todoItems.ts
└── pages
├── index.tsx
└── api
├── item
│ ├── [id].ts
└── items
├── index.ts
└── search.ts
```

</details>

<details>
<summary> 🪢 Tigris schema definition</summary>

[models/tigris/todoStarterApp/todoItems.ts](models/tigris/todoStarterApp/todoItems.ts) - The to-do list app
has a single collection `todoItems` that stores the to-do items in `todoStarterApp` database. The
Database and Collection get automatically provisioned by the [setup script](scripts/setup.ts).

This is an inspiration from Next.js based file system router. Create a folder or drop a schema file
inside database folder under `models/tigris/`, and you're able to instantly create Databases and
Collections in Tigris for your application.

</details>

<details>
<summary> 🌐 Connecting to Tigris</summary>

[lib/tigris.ts](lib/tigris.ts) - Loads the environment variables you specified previously in creating a Vercel project
section and uses them to configure the Tigris client.

</details>

<details>
<summary> ❇️ API routes to access data in Tigris collection</summary>

All the Next.js API routes are defined under `pages/api/`. We have three files exposing endpoints:

#### [`pages/api/items/index.ts`](pages/api/items/index.ts)

- `GET /api/items` to get an array of to-do items as Array<TodoItem>
- `POST /api/items` to add an item to the list

#### [`/pages/api/items/search.ts`](/pages/api/items/search.ts)

- `GET /api/items/search?q=query` to find and return items matching the given query

#### [`pages/api/item/[id].ts`](pages/api/item/[id].ts)

- `GET /api/item/{id}` to fetch an item
- `PUT /api/item/{id}` to update the given item
- `DELETE /api/item/[id]` to delete an item

</details>

# 🚀 Next steps

In a few steps, we learnt how to bootstrap a Next.js app using Tigris and deploy it on Vercel. Feel
free to add more functionalities or customize App for your use-case and learn more about
[Tigris data platform](https://docs.tigrisdata.com/overview/)

<!-- MARKDOWN LINKS & IMAGES -->

[typescript]: https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white
[typescript-url]: https://www.typescriptlang.org/
[vercel]: https://img.shields.io/badge/vercel-F22F46?style=for-the-badge&logo=vercel&logoColor=white
[vercel-url]: https://vercel.com/
[deploy-url]: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Ftigrisdata%2Ftigris-vercel-starter&project-name=todo-list-app-tigris&repo-name=todo-list-webapp-tigris&demo-title=My%20To-do%20list%20webapp&demo-description=A%20To-do%20list%20webapp%20using%20NextJS%20and%20Tigris&integration-ids=oac_Orjx197uMuJobdSaEpVv2Zn8
[next.js]: https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white
[next-url]: https://nextjs.org/
47 changes: 47 additions & 0 deletions examples/with-tigris/components/EachToDo.tsx
@@ -0,0 +1,47 @@
import Image from 'next/image'
import React from 'react'
import { TodoItem } from '../models/tigris/todoStarterApp/todoItems'
import styles from '../styles/EachToDo.module.css'

type Props = {
toDoItem: TodoItem
deleteHandler: (id?: number) => void
updateHandler: (item: TodoItem) => void
}
const EachTodo = ({ toDoItem, deleteHandler, updateHandler }: Props) => {
return (
<>
<li className={styles.each}>
<button
className={styles.eachButton}
onClick={() => {
updateHandler(toDoItem)
}}
>
<Image
src={toDoItem.completed ? '/circle-checked.svg' : '/circle.svg'}
layout="fixed"
width={20}
height={20}
alt="Check Image"
/>
<span
style={toDoItem.completed ? { textDecoration: 'line-through' } : {}}
>
{toDoItem.text}
</span>
</button>
<button
className={styles.deleteBtn}
onClick={() => {
deleteHandler(toDoItem.id)
}}
>
<Image src="/delete.svg" width={24} height={24} alt="Check Image" />
</button>
</li>
</>
)
}

export default EachTodo
14 changes: 14 additions & 0 deletions examples/with-tigris/components/LoaderWave.tsx
@@ -0,0 +1,14 @@
import React from 'react'
import styles from '../styles/LoaderWave.module.css'

const LoaderWave = () => {
return (
<div className={styles.holder}>
<div className={`${styles.loader} ${styles.l1}`}></div>
<div className={`${styles.loader} ${styles.l2}`}></div>
<div className={`${styles.loader} ${styles.l3}`}></div>
</div>
)
}

export default LoaderWave
28 changes: 28 additions & 0 deletions examples/with-tigris/lib/tigris.ts
@@ -0,0 +1,28 @@
import { DB, Tigris } from '@tigrisdata/core'

const DB_NAME = 'todoStarterApp'

declare global {
// eslint-disable-next-line no-var
var tigrisDb: DB
}

let tigrisDb: DB

// Caching the client because `next dev` would otherwise create a
// new connection on every file save while previous connection is active due to
// hot reloading. However, in production, Next.js would completely tear down before
// restarting, thus, disconnecting and reconnecting to Tigris.
if (process.env.NODE_ENV !== 'production') {
if (!global.tigrisDb) {
const tigrisClient = new Tigris()
global.tigrisDb = tigrisClient.getDatabase(DB_NAME)
}
tigrisDb = global.tigrisDb
} else {
const tigrisClient = new Tigris()
tigrisDb = tigrisClient.getDatabase(DB_NAME)
}

// export to share DB across modules
export default tigrisDb
22 changes: 22 additions & 0 deletions examples/with-tigris/models/tigris/todoStarterApp/todoItems.ts
@@ -0,0 +1,22 @@
import {
TigrisCollectionType,
TigrisDataTypes,
TigrisSchema,
} from '@tigrisdata/core/dist/types'

export const COLLECTION_NAME = 'todoItems'

export interface TodoItem extends TigrisCollectionType {
id?: number
text: string
completed: boolean
}

export const TodoItemSchema: TigrisSchema<TodoItem> = {
id: {
type: TigrisDataTypes.INT32,
primary_key: { order: 1, autoGenerate: true },
},
text: { type: TigrisDataTypes.STRING },
completed: { type: TigrisDataTypes.BOOLEAN },
}
6 changes: 6 additions & 0 deletions examples/with-tigris/next.config.js
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
swcMinify: true,
}

module.exports = nextConfig
23 changes: 23 additions & 0 deletions examples/with-tigris/package.json
@@ -0,0 +1,23 @@
{
"private": true,
"scripts": {
"predev": "APP_ENV=development npm run setup",
"dev": "next dev",
"build": "next build",
"postbuild": "APP_ENV=production npm run setup",
"start": "next start",
"setup": "npx ts-node scripts/setup.ts"
},
"dependencies": {
"@tigrisdata/core": "beta",
"next": "latest",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@types/node": "18.11.2",
"@types/react": "18.0.21",
"@types/react-dom": "18.0.6",
"typescript": "4.8.4"
}
}
9 changes: 9 additions & 0 deletions examples/with-tigris/pages/_app.tsx
@@ -0,0 +1,9 @@
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import React from 'react'

function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

export default MyApp