Next.js에서Preisma ORM 활용

36796 단어 nextPrismatech
Next.js에서 Preisma ORM을 가져오는 방법에 대해 설명합니다.

Next.js 프로젝트의 초기 형태 만들기


생성
$ mkdir hello-next-app && cd hello-next-app
$ npm init -y
$ npm install next react react-dom --save
$ npm install typescript @types/node @types/react --save-dev
$ code src/index.tsx
scr/index.tsx
export default function Index() {
  return <div>index</div>;
}
nextbuild이면typescript의 형식 정의를 생성하여 한번 구축합니다.
$ npx next build
구축 대상이 tsx가 있기 때문에next는tsconfig.json에서 생성next-env.d.ts.

Preisma 설정


의존에 추가합니다.
$ npm install @prisma/client@2 --save
$ npm install @prisma/cli@2 --save-dev
prisma 디렉터리에 모드를 추가합니다.이번에는 sqlite3을 선택하십시오.prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

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

model Post {
  authorId  Int?
  content   String?
  id        Int     @id @default(autoincrement())
  published Boolean @default(false)
  title     String
  author    User?   @relation(fields: [authorId], references: [id])
}

model User {
  email String  @unique
  id    Int     @id @default(autoincrement())
  name  String?
  posts Post[]
}
VS코드에서 문법을 돋보이게 하려면 Prisma - Visual Studio Marketplace를 넣는 것이 좋다.
migration
$ npx prisma migrate dev --preview-feature --name init
$ npx prisma generate # @prisma/client の型の生成
(이 일대의 API는 빈번하게 변화하여 곧 바뀔 것이다)
migration이 성공하면 prisma/dev.dbprisma/migrations를 생성해야 한다.
$ tree prisma/
prisma/
├── dev.db
├── migrations
│   └── 20201222113842_init
│       └── migration.sql
└── schema.prisma

Next.js에서Preisma 활용


인스턴스prisma client안에 발매된query를 보고 싶어서 로그 옵션에 지정lib/prisma.ts합니다.
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient({
  log: ["query", "error", "info", "warn"],
});
export default prisma;

export * from "@prisma/client";
준비됐습니다!querypages/index.tsx에서 프리스마를 두드려 보세요.
import type { GetServerSideProps } from "next";
import prisma from "../lib/prisma";

type Props = {
  count: number;
};

export const getServerSideProps: GetServerSideProps<Props> = async (ctx) => {
  const count = await prisma.user.count();
  return {
    props: {
      count,
    },
  };
};

export default function Index(props: Props) {
  return <div>user count: {props.count}</div>;
}
getServerSideProps()는 서버가 수행하기 때문에 Dead Code Elimination을 통해 클라이언트에 노출되지 않습니다.getServerSideProps 서버를 시작하고 로그를 보면서 엽니다npx next.http://localhost:3000로 나오나요?그때의 일지는 여기에 있다.
prisma:query SELECT COUNT(*) FROM (SELECT `dev`.`User`.`id` FROM `dev`.`User` WHERE 1=1 LIMIT ? OFFSET ?) AS `sub`

포스트의 투고


validation에서zed를 사용하고Form 라이브러리로react-final-form을 사용합니다.
$ npm install zod final-form react-final-form --save
title 콘텐츠를 받아 prisma 레코드를 만드는 API Route를 만듭니다.user count: 0
import type { NextApiHandler } from "next";
import prisma from "../../lib/prisma";
import * as z from "zod";

const requestBodySchema = z.object({
  title: z.string().min(1),
  content: z.string(),
});

const handler: NextApiHandler = async (req, res) => {
  try {
    const result = requestBodySchema.parse(req.body);
    await prisma.post.create({
      data: {
        title: result.title,
        content: result.content,
        published: true,
      },
    });
    res.json({
      ok: true,
    });
    return;
  } catch (error) {
    res.json({ ok: false, error });
  }
};
export default handler;
react-final-form으로 이 API를 post하는 Form을 제작한다.pages/api/createPost.ts
import { useCallback } from "react";
import { Form, Field } from "react-final-form";
import { useRouter } from "next/router";

export function PostForm() {
  const router = useRouter();
  const onSubmit = useCallback(async (formData) => {
    const res = await fetch("/api/createPost", {
      method: "POST",
      body: JSON.stringify(formData),
      headers: {
        "Content-Type": "application/json",
      },
    });
    const json = await res.json();
    if (json.ok) {
      router.push("/");
    } else {
      alert(JSON.stringify(json));
    }
  }, []);
  return (
    <Form
      onSubmit={onSubmit}
      render={({ handleSubmit }) => {
        return (
          <form onSubmit={handleSubmit}>
            <Field<HTMLInputElement>
              name="title"
              placeholder="title"
              render={(props) => {
                return (
                  <div>
                    <input
                      {...(props.input as any)}
                      style={{ width: "80vw" }}
                    />
                  </div>
                );
              }}
            />
            <Field<HTMLTextAreaElement>
              name="content"
              placeholder="content"
              render={(props) => {
                return (
                  <div>
                    <textarea
                      {...(props.input as any)}
                      style={{ width: "80vw", height: "300px" }}
                    />
                  </div>
                );
              }}
            />
            <button type="submit">Submit</button>
          </form>
        );
      }}
    />
  );
}
에 쓰여진 Form의 요점은submit이고 다음 API를 실행하는 것이다.
const res = await fetch("/api/createPost", {
  method: "POST",
  body: JSON.stringify(formData),
  headers: {
    "Content-Type": "application/json",
  },
});
조금 게으름을 피워서 실현하지 못하고 API로 실현하면 다시 얻는 것이 번거롭기 때문에 다시 자신의 페이지로 가서 다시 얻는다.
이걸 열심히 하면 포스트 리스트가 API화되어react-query로 캐시됩니다.
tannerlinsley/react-query: ⚛️ Hooks for fetching, caching and updating asynchronous data in React
index 페이지에서 트위터처럼 현재 메일박스 일람표를 보여 보세요.components/PostForm.tsx
import type { GetServerSideProps } from "next";
import React from "react";
import { PostForm } from "../components/PostForm";
import prisma, { Post } from "../lib/prisma";

type Props = {
  posts: Pick<Post, "id", "title" | "content">[];
};

export const getServerSideProps: GetServerSideProps<Props> = async (ctx) => {
  const posts = await prisma.post.findMany({
    select: {
      title: true,
      content: true,
      id: true,
    },
  });
  return {
    props: {
      posts,
    },
  };
};

export default function Index(props: Props) {
  return (
    <>
      <PostForm />
      <div>post count: {props.posts.length}</div>
      {props.posts.map((post) => {
        return (
          <div key={post.id}>
            <h3>{post.title}</h3>
            <p>{post.content}</p>
          </div>
        );
      })}
    </>
  );
}
서버를 시작하여 완성된 폼에서 투고해 보십시오.

현재 내부에서 발행된 조회
prisma:query BEGIN
prisma:query INSERT INTO `dev`.`Post` (`content`, `published`, `title`) VALUES (?,?,?)
prisma:query SELECT `dev`.`Post`.`id`, `dev`.`Post`.`authorId`, `dev`.`Post`.`content`, `dev`.`Post`.`published`, `dev`.`Post`.`title` FROM `dev`.`Post` WHERE `dev`.`Post`.`id` = ? LIMIT ? OFFSET ?
prisma:query COMMIT
이상.이 범위 안에서 그렇게 어렵지 않다고 느낀다.

너 이거 왜 썼어?


연말연시를 맞아 넥스트를 선택했다.나는 js에 관한 책을 쓰고 있다.유료 기사로 젠에서 판매할 예정입니다.이 기사를 유료책의 일부로 이 주제로 쓰면 어떨까?써 보았다.
그 장의 일부로서 전체적인 겹쳐진 틀의 장을 쓰려고 한다, 블리츠.js 및 Nextjs Flower를 확인 중입니다.
2021년은 풀스테이크 넥스트다.js 원년이라서 희망이 있어요.모든 js계 프레임워크를 시도해 봤습니다.
해보니 현재 상황은 prisma 외에는 결정타라고 할 만한 것이 없다.
처음에는 블리츠에 초점을 맞추고 싶었지만 오늘 발표한 리액트 서버 컴포니트, 블리츠의 isomorphism 같은 것도 비교적 간단하게 실현할 수 있어 블리츠의 장점 중 하나를 넥스트에 두었다.나는 js 호스트가 쉽게 흡수된다고 생각한다.블리츠를 일부러 잠글 필요는 없다고 생각해요.
Introducing Zero-Bundle-Size React Server Components – React Blog
그렇긴 한데, 넥스트.js+Prism이 아직 보급되지 않았기 때문에 이 기사를 먼저 무료로 공개하는 것이 좋겠다고 생각해서 투고했습니다.
유료판에는 이 외에도 다음과 같은 요소를 해설할 예정이다.
  • docker-compostgres를 통해prisma에서 연결
  • react-query 캐시 응답
  • Amazon RDS에서 Postgres
  • 준비
  • hygen을 통해 isomorphic API 생성
  • Vercel을 이용한 디버깅 마이그레이션
  • .환경 변수 관리
  • 및 Vecrel Secrets

    좋은 웹페이지 즐겨찾기