Nextの中のAPIの利用方法
Nextの中のAPIの利用方法
2021年3月30日
Nextの中のAPIの利用方法
Nextのフレームワークの中に、バックエンドとのカスタムAPIを実装する事ができます。 便利なのは、フレームワークの中に、フロントエンドとバックエンドを一緒に実装する事ができる事です。当たり前ですが、呼び出しは基本的にフロントエンド(Webブラウザで動作しているJavascript)が行って、処理はバックエンド(Webサーバー)側で行います。
前回の投稿で触れていますが、コードが動作する場所を意識して設計する必要があります!
APIの定義は?
Nextのテンプレートのプロジェクトを「create-next-app」を使って作成した場合、各ページのファイルを入れるフォルダとして「pages」というフォルダが作成されます。 この下に、「api」というフォルダも作成されていて、サンプルのファイルとして、「hello.js」というファイルが作成されています。このフォルダのファイルでAPIを定義します。
サンプルの「hello.js」の場合、「/api/hello」というURLがAPIのURLになります。 ファイル名のベース(拡張子の「.js(.ts)」)を取り除いた名前がAPIのURLになるという事になります。
従って、「backend.ts」というファイルを「api」フォルダの下に作った場合は、「/api/backend」というURLを指定するとAPIを呼び出すことができます。
Nextのテンプレートのプロジェクトを「create-next-app」を使って作成した場合、各ページのファイルを入れるフォルダとして「pages」というフォルダが作成されます。 この下に、「api」というフォルダも作成されていて、サンプルのファイルとして、「hello.js」というファイルが作成されています。このフォルダのファイルでAPIを定義します。
サンプルの「hello.js」の場合、「/api/hello」というURLがAPIのURLになります。 ファイル名のベース(拡張子の「.js(.ts)」)を取り除いた名前がAPIのURLになるという事になります。
従って、「backend.ts」というファイルを「api」フォルダの下に作った場合は、「/api/backend」というURLを指定するとAPIを呼び出すことができます。
APIの実装
APIの実際の処理は、「backend.ts」に記述します。 今回は、例としてFirebaseのデータベースからデータを取得するという処理紹介します。
backend.tsの例です。このAPIが呼び出されると、サーバー側でFirebaseのデータベースの「test」というコレクションにアクセスしてデータを取得してそのデータをフロントエンド(Webブラウザ)に返します。 今回はコマンド(command)は1種類だけですが、必要に応じて追加することができます。switch文に追加して、実際に処理をする関数を記述すれば、簡単に追加できます。
import admin from "../../lib/admin";
import { NextApiRequest, NextApiResponse } from "next";
import * as CONSTANT from "../../lib/constants";
export default async (req: NextApiRequest, res: NextApiResponse) => {
const command: string = req.body.command;
let result: boolean;
let data: Array<any> = [];
try {
switch (command) {
case CONSTANT.COMMAND_GET_LIST:
data = await get_list();
result = true;
break;
default:
data = [];
result = false;
break;
}
} catch (error) {
data = [];
result = false;
}
res.json({ success: result, data: data });
};
function get_list(): Promise<Array<any>> {
return new Promise((resolve) => {
admin
.firestore()
.collection("test")
.get()
.then(
(
querySnapshot: admin.firestore.QuerySnapshot<admin.firestore.DocumentData>
) => {
const list = [];
if (querySnapshot.size !== 0) {
for (let i = 0; i < querySnapshot.size; i++) {
const doc = querySnapshot.docs[i];
list.push(doc.data());
}
resolve(list);
} else {
resolve(list);
}
}
)
.catch((error: any) => {
console.log(error);
resolve([]);
});
});
}
APIの実際の処理は、「backend.ts」に記述します。 今回は、例としてFirebaseのデータベースからデータを取得するという処理紹介します。
backend.tsの例です。このAPIが呼び出されると、サーバー側でFirebaseのデータベースの「test」というコレクションにアクセスしてデータを取得してそのデータをフロントエンド(Webブラウザ)に返します。 今回はコマンド(command)は1種類だけですが、必要に応じて追加することができます。switch文に追加して、実際に処理をする関数を記述すれば、簡単に追加できます。
import admin from "../../lib/admin";
import { NextApiRequest, NextApiResponse } from "next";
import * as CONSTANT from "../../lib/constants";
export default async (req: NextApiRequest, res: NextApiResponse) => {
const command: string = req.body.command;
let result: boolean;
let data: Array<any> = [];
try {
switch (command) {
case CONSTANT.COMMAND_GET_LIST:
data = await get_list();
result = true;
break;
default:
data = [];
result = false;
break;
}
} catch (error) {
data = [];
result = false;
}
res.json({ success: result, data: data });
};
function get_list(): Promise<Array<any>> {
return new Promise((resolve) => {
admin
.firestore()
.collection("test")
.get()
.then(
(
querySnapshot: admin.firestore.QuerySnapshot<admin.firestore.DocumentData>
) => {
const list = [];
if (querySnapshot.size !== 0) {
for (let i = 0; i < querySnapshot.size; i++) {
const doc = querySnapshot.docs[i];
list.push(doc.data());
}
resolve(list);
} else {
resolve(list);
}
}
)
.catch((error: any) => {
console.log(error);
resolve([]);
});
});
}
APIの呼び出し
APIの呼び出しは、フロントエンド(Webブラウザ)側で行います。 この例では、「pages」の下の「index.tsx」から呼び出しています。
当たり前のことですが、バックエンド(Webサーバー)側とはネットワークを使ってコミュニケーションをするので、「axios」というモジュールを使っています。 HTTPのメソッド(例ではPOST)とAPIのURLを指定します。 データ(メッセージの本体:body)にはコマンドを指定します。 データベースのデータはバックエンド(サーバー)側で取得して、応答で返してくるという仕組みです。
これで、フロントエンドからFirebaseにアクセスしなくてもバックエンドで処理をして表示することが可能になります。
import * as React from "react";
import Head from "next/head";
import styles from "../styles/Home.module.css";
import axios from "axios";
import * as CONSTANT from "../lib/constants";
interface IProps {}
interface IState {
list: Array<any>;
}
export default class Home extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
list: [],
};
}
getList():void {
axios({
method: "POST",
url: CONSTANT.API,
data: {
command: CONSTANT.COMMAND_GET_LIST,
},
})
.then((res) => {
console.log(res.data);
this.setState({
list: res.data.data,
});
})
.catch((error: any) => {
this.setState({
list:[]
})
});
}
render() {
return (
<div className={styles.container}>
<h1>Home</h1>
<button onClick={() => this.getList()}>Get</button>
<table>
<thead>
<tr>
<th>name</th>
</tr>
</thead>
<tbody>
{this.state.list.map((item: any) => (
<tr key={item.name}>
<td>{item.name}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
APIの呼び出しは、フロントエンド(Webブラウザ)側で行います。 この例では、「pages」の下の「index.tsx」から呼び出しています。
当たり前のことですが、バックエンド(Webサーバー)側とはネットワークを使ってコミュニケーションをするので、「axios」というモジュールを使っています。 HTTPのメソッド(例ではPOST)とAPIのURLを指定します。 データ(メッセージの本体:body)にはコマンドを指定します。 データベースのデータはバックエンド(サーバー)側で取得して、応答で返してくるという仕組みです。
これで、フロントエンドからFirebaseにアクセスしなくてもバックエンドで処理をして表示することが可能になります。
import * as React from "react";
import Head from "next/head";
import styles from "../styles/Home.module.css";
import axios from "axios";
import * as CONSTANT from "../lib/constants";
interface IProps {}
interface IState {
list: Array<any>;
}
export default class Home extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
list: [],
};
}
getList():void {
axios({
method: "POST",
url: CONSTANT.API,
data: {
command: CONSTANT.COMMAND_GET_LIST,
},
})
.then((res) => {
console.log(res.data);
this.setState({
list: res.data.data,
});
})
.catch((error: any) => {
this.setState({
list:[]
})
});
}
render() {
return (
<div className={styles.container}>
<h1>Home</h1>
<button onClick={() => this.getList()}>Get</button>
<table>
<thead>
<tr>
<th>name</th>
</tr>
</thead>
<tbody>
{this.state.list.map((item: any) => (
<tr key={item.name}>
<td>{item.name}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
フロントエンドの実装の可能性
今回の例では、フロントエンドにJavascriptを使ってボタンのイベントの処理をしていますが、他にもいろいろな実装が可能です。
選択肢は
- データだけをバックエンドから取得してWebブラウザでレンダリング(描画)
- データもWebブラウザから直接取得してWebブラウザでレンダリング(描画)
- バックエンドでデータを取得して、表示データ(ページ)もバックエンドで作る
などが考えられます。
1の方法の場合は、Firebase admin SDKを使って、サーバー側からFirebaseにアクセスするのでセキュリティルールの設定が不要になるのと、利用者からはFirebaseのデータベースの構造(コレクション名など)はわかりません。 2の方法は、通常のフロントエンドで全てを処理する方法です。この方法は、Nextを使わなくてもReactで実現可能の機能です。ただ、他のページの処理も普通はあるのでこの、ページだけはフロントエンドで処理するという事はあるかと思います。 3の方法は、処理を基本的にバックエンドで行うという実装で、フロントエンドはJavascriptを使わないで実装することも可能になります。Javascriptを有効にしていないブラウザーでも動的な処理を行う事ができます。
Nextの良い点は、必要に応じてフロントエンドの処理を選べるところにあります。
オンライン決済などを行う場合は、処理をバックエンドで行う必要がある場合が多いので、Nextを使うとバックエンドも含めた形の実装が可能になるので便利です。
今回の例では、フロントエンドにJavascriptを使ってボタンのイベントの処理をしていますが、他にもいろいろな実装が可能です。
選択肢は
- データだけをバックエンドから取得してWebブラウザでレンダリング(描画)
- データもWebブラウザから直接取得してWebブラウザでレンダリング(描画)
- バックエンドでデータを取得して、表示データ(ページ)もバックエンドで作る
などが考えられます。
1の方法の場合は、Firebase admin SDKを使って、サーバー側からFirebaseにアクセスするのでセキュリティルールの設定が不要になるのと、利用者からはFirebaseのデータベースの構造(コレクション名など)はわかりません。 2の方法は、通常のフロントエンドで全てを処理する方法です。この方法は、Nextを使わなくてもReactで実現可能の機能です。ただ、他のページの処理も普通はあるのでこの、ページだけはフロントエンドで処理するという事はあるかと思います。 3の方法は、処理を基本的にバックエンドで行うという実装で、フロントエンドはJavascriptを使わないで実装することも可能になります。Javascriptを有効にしていないブラウザーでも動的な処理を行う事ができます。
Nextの良い点は、必要に応じてフロントエンドの処理を選べるところにあります。
オンライン決済などを行う場合は、処理をバックエンドで行う必要がある場合が多いので、Nextを使うとバックエンドも含めた形の実装が可能になるので便利です。
まとめ
この記事では、Nextの機能の一部として、フロントエンドとバックエンドのAPIを実装する例を紹介しました。Nextの実装は、必要に応じてバックエンドとフロントエンドの処理を使い分ける事ができるのが便利な点の一つです。
コードの実行場所をよく理解した上でバランスのよい実装ができるとより使いやすいアプリやサービスが実現できます。
この記事では、Nextの機能の一部として、フロントエンドとバックエンドのAPIを実装する例を紹介しました。Nextの実装は、必要に応じてバックエンドとフロントエンドの処理を使い分ける事ができるのが便利な点の一つです。
コードの実行場所をよく理解した上でバランスのよい実装ができるとより使いやすいアプリやサービスが実現できます。
コメント
コメントを投稿