Skip to content

vercelの「How to Build a Fullstack App with Next.js, Prisma, and PostgreSQL」チュートリアルでハマる

📅 May 17, 2021

⏱️4 min read

どうもこんちは、マラソン犬おじさんです。

Next.js、Prisma、PostgreSQLを使用してフルスタックアプリを構築する方法-Vercel Guides という神がかったチュートリアルがvercel様から出ていたので、早速試してました。 そして、盛大にハマったので、備忘録です。

ハマりどころ

githubがメールアドレスを返してくれない

next-authを使用して、ログイン周りを実装するのですが、チュートリアル通りに実装しても、emailがnullのままになります。

NextAuthのドキュメントを確認すると

Email address is not returned if privacy settings are enabled

とのこと。。。 Email | NextAuth.js

privacy settings?なんて設定した記憶はないがと思い、グーグル先生に質問したところ、

All newly created user accounts on GitHub.com now have the keep my email address private setting enabled by default.

デフォルトtrueらいし。。。 Your privacy on GitHub - GitHub Original Series / Support Protips - GitHub Support Community

そりゃ、当然メールアドレス返ってこないよね。

userモデルにメールアドレスも保存できるようにする

pages/api/auth/[...nextauth].ts ファイルを以下のような感じに修正しました。 signinしたあとに、もう一度githubにアドレスもらいにいってます。 (prismaもnext-authもまだ何もわかってないので、間違っていたら教えて下さい。)

// pages/api/auth/[...nextauth].ts
import { NextApiHandler } from "next";
import NextAuth, { NextAuthOptions } from "next-auth";
import Providers from "next-auth/providers";
import Adapters from "next-auth/adapters";
import prisma from "../../../lib/prisma";

const options = {
  providers: [
    Providers.GitHub({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
  ],
  adapter: Adapters.Prisma.Adapter({ prisma }),
  secret: process.env.SECRET,
  callbacks: {
    signIn: async (profile, account, metadata) => {
      const res = await fetch("https://api.github.com/user/emails", {
        headers: {
          Authorization: `token ${account.accessToken}`,
        },
      });
      const emails = await res.json();
      if (!emails || emails.length === 0) {
        return;
      }
      const sortedEmails = emails.sort((a, b) => b.primary - a.primary);
      profile.email = sortedEmails[0].email;
      return true
    },
  },
};

const authHandler: NextApiHandler = (req, res) => NextAuth(req, res, options);
export default authHandler;

デプロイする気のないコード

何故か、記事の公開・削除のためのapiを叩く処理のコードに localhost:3000 が含まれている・・・。開発環境だと問題ないが、このチュートリアルでは最終的にvercelにデプロイするので、この部分は不要。

async function publishPost(id: number): Promise<void> {
  await fetch(`/api/publish/${id}`, {
    method: 'PUT',
  })
  await Router.push('/')
}

async function deletePost(id: number): Promise<void> {
  await fetch(`/api/post/${id}`, {
    method: 'DELETE',
  })
  Router.push('/')
}

vercelデプロイ時にtype errorでコケる

prismaのインスタンスをグローバルで定義している部分。もちろん後から、勝手にprismaインスタンスをぶちこんでいるので、そのままでは、tsコンパイラーはエラーを吐く。 雑だけど、矢印のような感じでエラー吐かなくなる。(any

// lib/prisma.ts
import { PrismaClient } from '@prisma/client'
import { Prisma } from 'next-auth/adapters'

let prisma: PrismaClient
declare global {
  namespace NodeJS {
    interface Global {
      prisma: PrismaClient;
    }
  }
}

if (process.env.NODE_ENV === 'production') {
  prisma = new PrismaClient()
} else {
  if (!global.prisma) {
    global.prisma = new PrismaClient()
  }
  prisma = global.prisma
}

export default prisma

ということで、こんだけ修正したら、後は問題なくdeployまでできるはず。 ほいじゃーまた。

Next →
  • @masayuki031