TL;DR

O/Rマッパとしてprismaを使用して、簡単なCRUDをNext.jsと一緒に作成します。

Next.jsのセットアップ

なにはともあれNext.jsをセットアップします。

yarn create next-app --typescript

prismaのセットアップ

prismaをインストール

# install
yarn add @prisma/client
yarn add prisma --dev

# init
npx prisma init

.envが作成され、その中にDATABASE_URLが設定されています。今回はsqlite3を使います。

.env
DATABASE_URL="file:./dev.db"

schemaを書きます。とりあえず、titleとcontentがあれば良さそうです。

prisma/schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

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

generator client {
  provider = "prisma-client-js"
}

model Todo {
  id        Int      @default(autoincrement()) @id
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  title String @db.VarChar(255)
  content String?
}

準備ができたので、データベースを起動した後、migrationをし、prisma clientのセットアップをします。

npx prisma migrate dev --name init

migrateをすると自動的に@prisma/clientnode_modules配下に作成されます。明示的にnpx prisma generateをすることでも生成できます。

テーブルができているか一応チェックします。

sqlite3 prisma/dev.db
> .tables
Todo                _prisma_migrations
> .schema TODO
CREATE TABLE IF NOT EXISTS "Todo" (
    "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" DATETIME NOT NULL,
    "title" TEXT NOT NULL,
    "content" TEXT
);
Postgresの場合

herokuかなんかにデプロイする気がするので、postgresを使用する場合についても書いておきます。まず、postgresをdockerで用意しておきます。頻繁にpostgresのdockerを使っているので、使用するportは15432です。

version: "3"
services:
  db:
    image: postgres:13.3
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - 15432:5432
    volumes:
      - ./postgres:/var/lib/postgresql
volumes:
  postgres:

.envのDATABASE_URLを以下のように設定します。portを今回はいじっているのと、パスワード、ユーザーネームが設定されているので注意が必要です。

.env
DATABASE_URL="postgresql://postgres:postgres@localhost:15432/main?schema=public"

prisma clientの設定

libs以下にprisma clientの設定を作成しておきます。どんなクエリが投げられているか一応みたいなので、logにqueryを追加しています。

import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient({
  log: ["query", "error", "info", "warn"],
});
export default prisma;

export * from "@prisma/client";

CRUDできるAPIの作成

今回は単純な確認なので、メソッドの確認は行っていません。また、実際にはパスパラメタなどでIDを受け取ったほうがいいと思いますが、Next.jsでやるのは少し面倒だったので、全てデータの中で受け取っています。

Create

まず、Todoを作成するcreate-todoを作成します。

pages/api/create-todo.ts
import type { NextApiHandler } from "next"
import prisma from "../../libs/prisma"

const handler: NextApiHandler = async (req, res) => {
    try {
        await prisma.todo.create({data: {...req.body, updatedAt: new Date()}})
        res.status(200).send("ok");
    } catch (error) {
        console.log(error)
        res.status(500).json(error)
    }
}

export default handler;

yarn devで起動して、APIにPOSTを投げてみます。

curl -X POST -H "Content-Type: application/json" -d '{ "title": "test", "content": "Test Todo Items" }' localhost:3000/api/create-todo
# ok

READ

TODO LISTを取得するEND POINTを作成します。

pages/api/get-todos.ts
import type { NextApiHandler } from "next"
import prisma from "../../libs/prisma"

const handler: NextApiHandler = async (req, res) => {
    try {
        const todos = await prisma.todo.findMany();
        res.status(200).json(todos);
    } catch (error) {
        console.log(error)
        res.status(500).json(error)
    }
}

export default handler;

GETリクエストしてみます。ちゃんと作成されていることが分かります。

curl localhost:3000/api/get-todos | jq
[
  {
    "id": 1,
    "createdAt": "2021-11-09T00:01:37.223Z",
    "updatedAt": "2021-11-09T00:01:37.215Z",
    "title": "test",
    "content": "Test Todo Items"
  }
]

UPDATE

UPDATE用のAPIを作ります。

pages/api/update-todo.ts
import type { NextApiHandler } from "next"
import prisma from "../../libs/prisma"

const handler: NextApiHandler = async (req, res) => {
    if (!req.body.id) {
        res.status(400).send("Bad Request. need id!");
        return
    }
    try {
        await prisma.todo.update({data: {...req.body, updatedAt: new Date()}, where: {id: req.body.id}})
        res.status(200).send("ok");
    } catch (error) {
        console.log(error)
        res.status(500).json(error)
    }
}

export default handler;

curlでチェックします。

curl -X PUT -H "Content-Type: application/json" -d '{ "id": 1, "title": "test", "content": "Update Test Todo Items" }' localhost:3000/api/update-todo
# ok
curl localhost:3000/api/get-todos | jq
[
  {
    "id": 1,
    "createdAt": "2021-11-09T00:01:37.223Z",
    "updatedAt": "2021-11-09T00:12:38.526Z",
    "title": "test",
    "content": "Update Test Todo Items"
  }
]

contentとupdatedAtがたしかに更新されています。

Delete

最後にDelete部分を実装します。

pages/api/delete-todo.ts
import type { NextApiHandler } from "next"
import prisma from "../../libs/prisma"

const handler: NextApiHandler = async (req, res) => {
    try {
        await prisma.todo.delete({where: {id: req.body.id}})
        res.status(200).send("ok");
    } catch (error) {
        console.log(error)
        res.status(500).json(error)
    }
}

export default handler;

DELETできるか確認します。

curl -X DELETE -H "Content-Type: application/json" -d '{ "id": 1 }' localhost:3000/api/delete-todo
# ok
curl localhost:3000/api/get-todos | jq
# []

記事に間違い等ありましたら、お気軽に以下までご連絡ください

E-mail: illumination.k.27|gmail.com ("|" replaced to "@")

Twitter: @illuminationK

当HPを応援してくれる方は下のリンクからお布施をいただけると非常に励みになります。

Ofuse

Other Articles

Privacy Policy

Copyright © illumination-k 2020-2021.