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までできるはず。 ほいじゃーまた。