1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Hexabase TypeScript SDKを使ったデモ(チャットアプリ)

Posted at

Hexabase(ヘキサベース)は企業においても安心して利用できるBaaS(Backend as a Service)を提供しています。多くのBaaSがそうであるように、主にフロントエンド開発者に利用してもらいたいと考えています。そこで現在、TypeScript SDKの開発が進められています。

この記事ではv2系になって新しくなったHexabase TypeScript SDKのインストールと、データストア(クラウドデータベース)の通知機能を使ったチャットアプリの実装を紹介します。

デモ

コードは以下で公開しています。

hexabase/sample-nextjs-chat

インストール

インストールはnpmやyarnを使って行います。

# npmの場合
npm install @hexabase/hexabase-js

# yarnの場合
yarn add @hexabase/hexabase-js

インポート

インポートすると、 HexabaseClient というオブジェクトが取得できます。

import { HexabaseClient, Item } from "@hexabase/hexabase-js";

初期化

HexabaseClientを初期化します。

// 本番閑居向け
const client = new HexabaseClient();

// 開発環境向け
const client = new HexabaseClient('dev');

なお、すでに認証済みだった場合は setToken メソッドを使ってトークンをセットすることもできます。

client.setToken(token);

認証

Hexabaseでは業務利用を想定しているため、利用する際に認証情報が必須になります。最初はメールアドレスとパスワードで認証し、その後はトークンを使ってGraphQLにアクセスします。 client を使って処理します。

初回の認証は次のようになります。emailとパスワード、またはトークンが必須です。

await client.login({email, password, token});

後はこの client に対して処理を行います。

認証の判定

ログイン済みかどうかは client.currentUsernull かどうかで判定できます。今回はそれをステートに入れることで、ログイン判定と画面の出し分けを行っています。

const [loggedIn, setLoggedIn] = useState<boolean>(false);

useEffect(() => {
	const token = localStorage.getItem('token');
	if (token) init(token);
}, []);

const init = async (token: string) => {
	await client.setToken(token);
	await client.setWorkspace(process.env.NEXT_PUBLIC_WORKSPACE_ID!);
	setLoggedIn(true);
}

return (
	<>
		{ loggedIn ?
			<Chat client={client} />
		: <Login success={success} />}
	</>
)

認証画面

ログイン画面は components/login.tsx にて実装しています。メールアドレスとパスワードで認証を行っています。認証が通れば、 success に対してトークン文字列を送っています。

const [form, setForm] = useState<FormType>({
	email: '',
	password: '',
	errorMessage: '',
});

const login = async (e: React.SyntheticEvent<HTMLFormElement> | React.MouseEvent<HTMLButtonElement>) => {
	e.preventDefault();
	const bol = await client.login({email: form.email, password: form.password});
	if (bol) {
		params.success(client.tokenHxb);
	} else {
		setForm({...form, errorMessage: 'ログインに失敗しました。'});
	}
};

image.png

チャットルーム一覧画面

認証が通ったら <Chat /> を表示します。これは components/chat.tsx にて実装しています。Hexabase SDKのQueryを使って、チャットルーム一覧を取得しています。

const [rooms, setRooms] = useState<Item[]>([]);

useEffect(() => {
	getRooms();
}, []);

const getRooms = async () => {
	const rooms = await client.query(process.env.NEXT_PUBLIC_PROJECT_ID!)
		.from(process.env.NEXT_PUBLIC_DATASTORE_CHAT_ID!)
		.select('*');
	setRooms(rooms);
}

一覧は画面に表示し、 Next.js の Linkを使って /{room.id} で遷移できるようにします。

{rooms.map((room, i) => {
	return (
		<div key={i}>
			<Link href={`/${room.id}`}>
				{room.get<string>('name')}
			</Link>
		</div>
	)
})}

image.png

チャット画面

チャット画面は app/[id]/page.tsx にて実装しています。この画面にはURL直打ちでアクセスする可能性を考慮しています。まずルームの取得、そしてこれまでのメッセージ一覧を取得します。

// ルームのステート
const [room, setRoom] = useState<Item | undefined>(undefined);
// メッセージのステート
const [messages, setMessages] = useState<ItemHistory[]>([]);
// 新規入力されたメッセージのステート
const [comment, setComment] = useState<string>('');

// 最初にルームを取得する
useEffect(() => {
	getRoom();
}, []);

// ルームを取得する処理
const getRoom = async () => {
	// Hexabaseの初期化
	await initHexabase();
	// プロジェクト、データストア、アイテム(ルーム)の取得
	const project = await client.currentWorkspace?.project(process.env.NEXT_PUBLIC_PROJECT_ID!);
	const datastore = await project?.datastore(process.env.NEXT_PUBLIC_DATASTORE_CHAT_ID!);
	const room = await datastore?.item(id);
	if (!room) return;
	// ルームのステートを更新
	setRoom(room);
	// これまでのメッセージを取得
	setHistory(room);
	// ルームの更新を監視
	subscribe(room);
};

// Hexabaseの初期化処理
const initHexabase = async () => {
	const token = localStorage.getItem('token');
	if (!token) return;
	await client.setToken(token);
	await client.setWorkspace(process.env.NEXT_PUBLIC_WORKSPACE_ID!);
};

// これまでのメッセージを取得する処理
const setHistory = async (room: Item) => {
	const histories = await room?.histories();
	// 空文字列、または __refresh__ は除外
	setMessages((histories || [])
		.filter(history => history.comment !== '' && history.comment !== '__refresh__'));
}

// ルームの更新を監視する処理
const subscribe = (room: Item) => {
	// 更新通知がきたら、これまでのメッセージを取得し直す
	room?.subscribe('update', history => setHistory(room));
}

messages は一覧表示します。ログインユーザーと投稿者が同じ場合は、データを削除できるようにします。

<List spacing={3}>
	{messages.map((message, i) => {
		return (
			<ListItem key={i}>
				{message.comment} by {message.user?.userName}
				{message.user?.userName === client.currentUser?.userName && <Button onClick={() => remove(message)}>削除</Button>}
			</ListItem>
		)
	})}
</List>

image.png

新規メッセージの投稿

フォームで新しいメッセージを入力します。

<form onSubmit={submit}>
	<input type="text" id="comment" value={comment} onChange={e => setComment(e.target.value)} />
	<button type="submit">送信</button>
</form>

submit 処理で、新しいメッセージを投稿します。

// メッセージを送信する処理
const submit = async (e: React.SyntheticEvent<HTMLFormElement>) => {
	e.preventDefault();
	const history = room!.comment();
	history.set('comment', comment);
	await history.save();
	setComment('');
};

保存されると、 subscribe で登録した処理が実行され、 setHistory でメッセージ一覧を更新します。

// ルームの更新を監視する処理
const subscribe = (room: Item) => {
	// 更新通知がきたら、これまでのメッセージを取得し直す
	room?.subscribe('update', history => setHistory(room));
}

image.png

メッセージの削除

メッセージの削除は一覧の remove 関数呼び出しで行います。メッセージを削除しても通知されないので、特別に __refresh__ というメッセージを送っています。このメッセージの通知を受け取ったら、一覧を強制リフレッシュしています。

// メッセージを削除する処理
const remove = async (history: ItemHistory) => {
	await history.delete();
	// 強制更新させるメッセージを送信
	const deleteMessage = room!.comment();
	deleteMessage.set('comment', '__refresh__');
	await deleteMessage.save();
}

// ルームの更新を監視する処理
const subscribe = (room: Item) => {
	// 更新通知がきたら、これまでのメッセージを取得し直す
	room?.subscribe('update', history => setHistory(room));
}

// これまでのメッセージを取得する処理
const setHistory = async (room: Item) => {
	const histories = await room?.histories();
	// 空文字列、または __refresh__ は除外
	setMessages((histories || [])
		.filter(history => history.comment !== '' && history.comment !== '__refresh__'));
}

APIの呼び出し回数を減らすなら、メッセージのIDを一緒に送ってフィルタリングする方法でも良さそうです。

まとめ

SDKを使うことで、Hexabaseを使ったアプリに簡単なチャット機能を追加できます。ぜひWebアプリケーション開発に活用してください。

Hexabaseには他にもファイルストレージやスクリプトなどの機能があります。それらの機能も利用してください。

Hexabase | 新規事業向け開発・競争領域でのDX実現をサポート

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?