ユーザAPIの実装
データ型
frontend/src/types/data.d.ts
// API Context
export type ApiContext = {
  apiRootUrl: string | undefined;
};
// ↓追加
// ユーザ
export type User = {
  id: string;
  email: string;
};
// ↑追加
API
ユーザ取得API
frontend/src/services/users/getUser.ts
import { ApiContext, User } from '@/types/data';
import { fetcher } from '@/utils';
const context: ApiContext = {
  apiRootUrl: process.env.NEXT_PUBLIC_API_BASE_URL,
};
/**
 * ユーザ取得API
 * @param email - emailアドレス
 * @returns ユーザ
 */
const getUser = async (email: string): Promise<User> => {
  const res = await fetcher(`${context.apiRootUrl?.replace(/\/$/g, '')}/users/?email=${email}`, {
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    cache: 'no-store',
  });
  return await res.users.at(0);
};
export default getUser;
ユーザ登録API
frontend/src/services/users/postUser.ts
import { ApiContext, User } from '@/types/data';
import { fetcher } from '@/utils';
const context: ApiContext = {
  apiRootUrl: process.env.NEXT_PUBLIC_API_BASE_URL,
};
/**
 * ユーザ登録API
 * @param email - emailアドレス
 * @returns ユーザ
 */
const postUser = async (email: string): Promise<User> => {
  const body = {
    email: email,
  };
  return await fetcher(`${context.apiRootUrl?.replace(/\/$/g, '')}/users/`, {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });
};
export default postUser;
emailアドレスとデータベース上のユーザとの紐付け
frontend/src/services/users/connectUser.ts
'use server';
import { auth } from '@/auth';
import getUser from './getUser';
import postUser from './postUser';
/**
 * サインインユーザとデータベース上のユーザとを紐付ける。
 */
const connectUser = async (): Promise<void> => {
  const session = await auth();
  if (session) {
    // サインインユーザのemailアドレスがデータベース上に登録されていれば、そのユーザの情報を取得する。
    const user = await getUser(session.user?.email!);
    // データベース上に登録されていなければ、そのユーザを新規登録する。
    if (!user) {
      await postUser(session.user?.email!);
    }
  }
};
export default connectUser;
サインイン直後の紐付け
各URLに対応するページからconnectUser()を呼び出すことで、サインイン直後にサインインユーザとデータベース上のユーザとを紐付けます。
frontend/src/app/page.tsx
import { SessionProvider } from 'next-auth/react';
import React from 'react';
import HelloAccount from './components/HelloAccount';
import connectUser from '@/services/users/connectUser'; // <- 追加
const Index = async () => { // <- asyncを追加
  await connectUser(); // <- 追加
  return (
    <>
      <section>
        <SessionProvider>
          <HelloAccount />
        </SessionProvider>
      </section>
    </>
  );
};
export default Index;
frontend/src/app/myaccount/page.tsx
import React from 'react';
import { auth } from '@/auth';
import connectUser from '@/services/users/connectUser'; // <- 追加
const MyAccountPage = async () => {
  await connectUser(); // <- 追加
  const session = await auth();
  if (!session) return <div>Not authenticated</div>;
  return (
    <>
      <h1>Server Side</h1>
      <pre>{JSON.stringify(session, null, 2)}</pre>
    </>
  );
};
export default MyAccountPage;
ブラウザで下記URLにアクセスし、サインインしてください。
初回のサインインの場合、usersテーブルにユーザデータが登録されます。
recsys_full=# SELECT * FROM users;
2回目以降のサインインの場合、emailアドレスをキーに、usersテーブル内の既存のユーザデータと紐付けられます。
参考
- 株式会社オープントーン,佐藤大輔,伊東直喜,上野啓二,『実装で学ぶフルスタックWeb開発 エンジニアの視野と知識を広げる「一気通貫」型ハンズオン』,翔泳社,2023.
    
- 6-9-2 参照系機能のつなぎ込み
 
 - 【Next.js13】最新バージョンのNext.js13をマイクロブログ構築しながら基礎と本質を学ぶ講座 | Udemy
    
- SSRとSSGってなに?使い分けはどうするの?
 
 - 【Reactアプリ開発】3種類のReactアプリケーションを構築して、Reactの理解をさらに深めるステップアップ講座 | Udemy
    
- 実際にポケモンのデータを取得してみよう