前回はデータベースに全国郵便番号データをCSV形式で入れる事ができたので、今回は実際にサーバーで郵便番号が検索できるフォームを作成します。前回の記事でPostgres(データベース)を確認してみるとencoding collate ctypeがen_US.UTF-8
になっていて、ログ確認時にブラウザで文字化けを起こしている挙動を得ました。なので、新たにaddressというデータベースを作りエンコーディングをja_JP.UTF-8
に書き換えることにしました。
create database address template template0 ENCODING = 'UTF8' LC_COLLATE = 'ja_JP.UTF-8' LC_CTYPE = 'ja_JP.UTF-8';
同時にテーブルも作り直し、以下の通り作成し直しました。
Table "public.address"
Column | Type | Collation | Nullable | Default
----------------+-------------------+-----------+----------+---------
post | character(21) | | not null |
prefectures | character varying | | not null |
municipalities | character varying | | not null |
address | character varying | | not null |
\COPY
でCSVファイルをデータベースに保存し、select * from address;
で確認。
post | prefectures | municipalities | address
--------------+-------------+--------------------+----------------------------------------------
600000 | 北海道 | 札幌市中央区 | 以下に掲載がない場合
640941 | 北海道 | 札幌市中央区 | 旭ケ丘
600041 | 北海道 | 札幌市中央区 | 大通東
600042 | 北海道 | 札幌市中央区 | 大通西(1~19丁目)
640820 | 北海道 | 札幌市中央区 | 大通西(20~28丁目)
600031 | 北海道 | 札幌市中央区 | 北一条東
600001 | 北海道 | 札幌市中央区 | 北一条西(1~19丁目)
640821 | 北海道 | 札幌市中央区 | 北一条西(20~28丁目)
:
結局、ブラウザ確認時の文字化けは解消されずでしたが。細かな検証は今後の課題として、進んで行きたいと思います。今回は、React(JavaScriptのライブラリ)のSSR(サイバーサイドレンダリング)を可能にするJavaScriptのフレームワークであるNext.js
を導入し実装していきたいと思います。node.js
がインストールされていない方はこちらをインストールして下さい。チュートリアルに従って、ターミナルから次のコマンドを実行します。
npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"
ディレクトリであるNESTJS-BLOG
が作成され、各パッケージが入りました。
続けてIDE(統合開発環境)を整えます。開発時からエラーに気づけるように設定を書く為、タッチコマンドでtsconfig.json
を入れ、npmやtypescriptなどのパッケージをsave-devの方にインストール。一度npm run dev
を実行します。
touch tsconfig.json
npm install --save-dev typescript @types/react
npm run dev
の準にターミナルで実行すると、以下の画面になり、
http://localhost:3000
で確認すると、無事ローカル上で挙動を確認できました。
ここまで来たら、いよいよ本題であるページのレンダリング(データをもとに表示内容を作る)やルーティング(pagesディレクトリ内のファイルの結び付け)、Reactフック(クラスを作成せずに、状態やその他のReact機能を使用を可能にするもの)を使ってコードを書いていきましょう。pagesディレクトリ内にapiディレクトリを作ってaddress.tsファイルを作成し記述していきます。まずはSequelizeを使用してデータベースを呼び出します。Sequelizeとは、Node.js上でORMを提供するライブラリです。以下のコマンドでインストールしましょう。
npm install --save sequelize
構文・継承を用いたclass 子クラス extends 親クラス
でAddressとModelを定義し、データベースのテーブルに文字列で値を渡します。init()
内に各テーブルの要素を入れます。Sequelizeでデータベースのカラムを変更せずModelを定義するために、主キーに対応するpost
(カラム)にprimaryKey:true
を追加。createdAt,updatedAtを追加しないfreezeTableName:true
とtimestamps:false
を利用してテーブルのスキーマを現状の形で使えるようにします。郵便番号データをasyncで以下のように記述。
import { Sequelize, Model, DataTypes } from 'sequelize';
const sequelize = new Sequelize({
database: 'address',
password: null,
dialect: 'postgres',
port: 5432,
host: 'localhost',
timezone: 'Asia/Tokyo',
});
class Address extends Model {}
Address.init({
post: {type:DataTypes.STRING,primaryKey:true},
prefectures: DataTypes.STRING,
municipalities: DataTypes.STRING,
address: DataTypes.STRING
}, { sequelize, modelName: 'address',freezeTableName:true,timestamps:false });
export default async(req, res) => {
await sequelize.sync();
console.log(await Address.count());
const address = await Address.findOne({
where: {
post: req.query['post'],
}
});
console.log(address)
res.status(200).send(JSON.stringify(address))
}
pagesディレクトリ内にあるindex.jsファイル
をindex.tsx
に書き換えてコードを以下のように記述します。
import Head from 'next/head'
import React, { Props } from "react";
const Home = (props: Props) => {
const [value, setValue] = React.useState("");
const [prefectures, setPrefectures] = React.useState("");
const [municipalities, setMunicipalities] = React.useState("");
const [address, setAddress] = React.useState("");
React.useEffect(()=>{
fetch('/api/address?post='+value)
.then(response => response.json())
.then(data => {
if(data !== null){
setPrefectures(data.prefectures)
setMunicipalities(data.municipalities)
setAddress(data.address)}});
},[value])
return (
<div>
<h3>郵便番号を入力して下さい</h3>
<label style={{ display: "block" }}>
<input type='text'
placeholder="半角数字で入力"
maxLength={8}
size={14}
value={value}
onChange={event => setValue(event.target.value.replace("-",""))} />
</label>
{prefectures!=""&& <h3>住所</h3>}
{prefectures!=""&&
<div><label style={{ display: "block" }}>
<input type='text'
value={prefectures}
onChange={event => setValue(event.target.value)} /><br/>
</label>
<label style={{ display: "block" }}>
<input type='text'
value={municipalities}
onChange={event => setValue(event.target.value)} /><br/>
</label>
<label style={{ display: "block" }}>
<input type='text'
value={address}
onChange={event => setValue(event.target.value)} /><br/>
</label>
</div>}
</div>
)
}
export default Home;
ターミナルで実行してみます。
nmp run dev
http://localhost:3000/
にて挙動を検証。
郵便番号を入力してみます!
なんとか、それらしきものが出来上がりました。