When discussing easy-to-set-up, cloud-based databases, platforms like Supabase often come to mind.
However, if you're looking for something that can be used even by non-developers, something nearly everyone is familiar with: Google Sheets is likely the first tool you'll think of š„
In the following snippet, I'll show the minimal steps required to implement CRUD data directly to/from Google Sheets.
Requirements:
- Google Sheet -> https://sheets.new/. Add example headers:
Email
,Date
,Notes
(first row) - GSheet API Auth keys
To get GSheet API Keys, we need:
Setup
Install dependencies:
pnpm add google-auth-library google-spreadsheet dotenv
Code
GSHEET_API_PRIVATE_KEY='-----BEGIN PRIVATE KEY...'
GSHEET_API_CLIENT_EMAIL='[email protected]'
import {JWT} from 'google-auth-library'
import {GoogleSpreadsheet} from 'google-spreadsheet'
import 'dotenv/config' // don't forget to create .env file
const GSHEET_API_CLIENT_EMAIL = process.env.GSHEET_API_CLIENT_EMAIL // example: [email protected]
const GSHEET_API_PRIVATE_KEY = process.env.GSHEET_API_PRIVATE_KEY // example: -----BEGIN PRIVATE KEY...
if (!GSHEET_API_CLIENT_EMAIL || !GSHEET_API_PRIVATE_KEY) {
throw new Error('Provide GSHEET_API_CLIENT_EMAIL and GSHEET_API_PRIVATE_KEY')
}
async function getDocument(sheetId) {
const serviceAccountAuth = new JWT({
email: GSHEET_API_CLIENT_EMAIL,
key: GSHEET_API_PRIVATE_KEY,
scopes: ['https://www.googleapis.com/auth/spreadsheets']
})
const doc = new GoogleSpreadsheet(sheetId, serviceAccountAuth)
await doc.loadInfo()
return doc
}
// sheet ID could found in the URL: https://docs.google.com/spreadsheets/d/<SHEET_ID>/edit?gid=0#gid=0\
// example: 1-HlukgKZtVA-Qjkb3v96JYasdgqkdZBCJ1o7z-aEDZPk
const SHEET_ID = 'sheet_id'
const getSheet = async () => {
const doc = await getDocument(SHEET_ID)
return await doc.sheetsByIndex[0]
}
async function getRows() {
const sheet = await getSheet()
return sheet.getRows()
}
getRows().then(e => console.log(e.toObject()))
Execute:
node ./gsheet.mjs
You should now see your data in the console ā
Create
async function addRow(item) {
const sheet = await getSheet()
return sheet.addRow(item)
}
addRow({Email: `example${new Date().getDate()}@example.com`, Date: '01-01-1971', Note: 'Note'})
Delete
async function deleteRow(index) {
const rows = await getRows()
return rows[index].delete()
}
deleteRow(0)
Update
async function updateRow(index, patch) {
const rows = await getRows()
const item = rows[index]
Object.entries(patch).map(([key, value]) => {
item.set(key, value)
})
return item.save()
}
updateRow(0, {Email: '[email protected]'})
Result
Overall, using Google Sheets as a temporary database offers several benefits:
- Can be set up quickly ā ideal for POCs or prototypes
- Almost free ā service accounts have usage limits before incurring charges, but in my experience, I have never reached that point
- Includes built-in permissions and version history
- Most people are familiar with Google Sheets or Excel
But overall, you should still treat it as technical debt and remember that it is obviously not scalable. So, if you have time or long-term plans for the project, start with tools designed for that purpose.
Nextjs
Now let's implement the Next.js API routes:
import {NextResponse} from 'next/server'
import {getRows, addRow, deleteRow, updateRow} from './gsheet.ts'
export async function GET() {
const rows = await getRows()
return NextResponse.json(rows.map(r => r.toObject()))
}
export async function POST(req: Request) {
const body = await req.json()
const row = await addRow(body)
return NextResponse.json(row.toObject())
}
export async function DELETE(req: Request) {
const body = await req.json()
await deleteRow(body.index)
return NextResponse.json({success: true})
}
export async function PUT(req: Request) {
const body = await req.json()
const row = await updateRow(body.index, body.patch)
return NextResponse.json(row.toObject())
}
Links
- Full code: https://gist.github.com/ra2dev/e5bfda750a002829297fa1dadcaf831c
google-spreadsheet
library docs - https://theoephraim.github.io/node-google-spreadsheet/#/