View on GitHub

ユーザAPIの実装

Home

ユーザ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テーブル内の既存のユーザデータと紐付けられます。

参考

  1. 株式会社オープントーン,佐藤大輔,伊東直喜,上野啓二,『実装で学ぶフルスタックWeb開発 エンジニアの視野と知識を広げる「一気通貫」型ハンズオン』,翔泳社,2023.
    • 6-9-2 参照系機能のつなぎ込み
  2. 【Next.js13】最新バージョンのNext.js13をマイクロブログ構築しながら基礎と本質を学ぶ講座 | Udemy
    • SSRとSSGってなに?使い分けはどうするの?
  3. 【Reactアプリ開発】3種類のReactアプリケーションを構築して、Reactの理解をさらに深めるステップアップ講座 | Udemy
    • 実際にポケモンのデータを取得してみよう