wheatandcatの開発ブログ

React Nativeで開発しているペペロミア & memoirの技術系記事を投稿してます

T3 Stack × Supabaseで本格的なサービスを作ってみる①

作りたいwebサービスが出来たので気になっていたT3 Stackを使用して実装してみたので紹介

create.t3.gg

サービスについては、まだ開発中なので、何回か記事にする予定

リポジトリ

github.com

作成中のWebサービス

oomaka.vercel.app

  • サービス名: OOMAKA
  • URL: https://oomaka.vercel.app
  • 概要: 大まかに未来の予定を可視化するサービス
  • ※まだログアウトの実装がミスっているので現在修正中 😅

T3 Stackとは

最近、話題のWebアプリーケーション開発の構成で以下の技術を使用している。

この構成で簡単に環境構築できるコマンドラインツールが以下で提供されている。

create.t3.gg

今回のサービスも上記のコマンドラインツールを使って実装

使用技術

実装の紹介

以下のコマンドラインを実行して、環境を構築

$ pnpm create t3-app@latest

Supabaseの接続は環境変数(.env)を以下を設定すればOK
DATABASE_URLの値はSupabseのコンソールの接続情報から取得可能

■ .env

# Prisma
# https://www.prisma.io/docs/reference/database-reference/connection-urls#env
DATABASE_URL="postgresql://postgres:*****@db.*****.supabase.co:****/postgres"

ログインはDiscordを使用
こちらも以下の環境変数を設定すればOK

■ .env

# Next Auth Discord Provider
DISCORD_CLIENT_ID="************"
DISCORD_CLIENT_SECRET="************"

上記でログインとデータベースの接続は完了

まずはDBの構築から実装
DBの構築はPrismaのスキーマファイルから作成

prisma/schema.prisma

model Url {
    id       String     @id @default(cuid())
    userId   String?
    schedule Schedule[]
}

model Schedule {
    id        String   @id @default(cuid())
    urlId     String
    date      DateTime
    day       Int?
    emoji     String?  @db.VarChar(5)
    text      String   @db.VarChar(10)
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
    url       Url      @relation(fields: [urlId], references: [id], onDelete: Cascade)

    @@index([urlId, date, day])
}

以下のコマンドでマイグレーションを実行

$ npx prisma migrate dev --name init

以下のコマンドでローカルで起動

$ pnpm dev

ログインについては以下の感じで実装できる

src/pages/index.tsx

import { signIn, signOut, useSession } from "next-auth/react";

(略)

  // ログインしている場合は sessionDataからログイン情報が取得できる
  const { data: sessionData } = useSession();

  // signIn()、signOut()を参照することでログイン/ログアウトを実装できる

APIアクセスはAPI Routesを使用
フロントエンドからのAPIアクセスはtRPCを使用、DBアクセスにはPrismaを使用してデータを取得

まず、APIの実装は以下の通りに実装

src/server/api/routers/schedule.ts

export const scheduleRouter = createTRPCRouter({
  ()
  fetchInPeriod: publicProcedure
    .input(
      z.object({
        urlId: z.string(),
        startDate: z.date(),
        endDate: z.date(),
      })
    )
    .query(async ({ ctx, input }) => {
      const schedules = await ctx.prisma.schedule.findMany({
        where: {
          urlId: input.urlId,
          date: {
            gte: input.startDate,
            lte: input.endDate,
          },
        },
        orderBy: {
          day: "asc",
        },
      });
      return schedules;
    }),

上記のAPIをフロントエンドから呼ぶ場合は以下の通りに実装

src/features/schedules/components/Items.tsx

  const schedules = api.schedule.fetchInPeriod.useQuery(
    {
      urlId: props.urlId,
      startDate: props.date.toDate(),
      endDate: props.date.endOf("month").toDate(),
    }
  );

tRPCとPrismaを使用して実装しているのでデータ取得については以下のようにコーディングで補完が効くので開発体験は、かなり良い感じに実装できる。

上記のような感じでWebアプリのベース部分である認証、APIアクセス、データベースアクセスがサクッと実装できる

Webアプリが出来たら以下を参考にvercelにデプロイ

create.t3.gg

これでWebアプリのリリースまで実装完了できる

まとめ

T3 Stack はサーバーサイド、フロントエンドが一括管理できる & 型安全が簡単に担保できて、非常に開発体験が良かった。
サクッとWebアプリを作りたい時は、かなり良い感じの構成だったので、今後も使っていくと思います。