はじめに
DB接続してデータを管理できる最低限のアプリを30分程度で作ります。
今回はいろいろあって、訪れた飲食店を評価し、身内におすすめするときの参考にできるアプリとしました。
あくまで骨組みまでなので、これを基に機能を追加していいものが作れたらと思います。
SQlite環境構築~テーブル作成まで
以下のURLにアクセスして環境にあったもの(今回はsqlite-tools-win32-x86-.zip)をダウンロードして、任意のフォルダに配置(今回はCドライブ直下にフォルダを作成)
https://sqlite.org/download.html
コマンドプロンプトでsqlite3.exe を置いたフォルダに移動し、以下のコマンドを順に実行
①sqlite3 restaurants.db
②CREATE TABLE IF NOT EXISTS restaurants (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, location TEXT, cuisine TEXT, rating INTEGER);
③.table
③を実行後restaurantsテーブルが作成されていることを確認する。
Node.jsでサーバ側の処理を作成
C:\eval_restaurantsフォルダを作成。以下のコマンドを実行。
npm init -y
npm install express sqlite3 cors
package.jsonファイルを作成+必要なパッケージのインストールを実施。
そしてC:\eval_restaurantsフォルダ直下にserver.jsファイルを作成して以下のコードを入力する。
const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const cors = require('cors');
const app = express();
const port = 5000;
// CORS設定
app.use(cors());
app.use(express.json());
// SQLiteデータベース接続
const db = new sqlite3.Database('./restaurants.db', (err) => {
if (err) {
console.error('データベース接続エラー:', err.message);
} else {
console.log('データベースに接続されました');
}
});
// データベース初期設定
db.serialize(() => {
db.run(`
CREATE TABLE IF NOT EXISTS restaurants (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
location TEXT,
cuisine TEXT,
rating INTEGER
)
`);
});
// APIエンドポイント
// すべてのレストラン情報を取得
app.get('/api/restaurants', (req, res) => {
db.all('SELECT * FROM restaurants', [], (err, rows) => {
if (err) {
res.status(500).json({ error: err.message });
return;
}
res.json({ data: rows });
});
});
// 新しいレストラン情報を追加
app.post('/api/restaurants', (req, res) => {
const { name, location, cuisine, rating } = req.body;
db.run(
`INSERT INTO restaurants (name, location, cuisine, rating) VALUES (?, ?, ?, ?)`,
[name, location, cuisine, rating],
function (err) {
if (err) {
res.status(500).json({ error: err.message });
return;
}
res.json({ id: this.lastID });
}
);
});
app.listen(port, () => {
console.log(`サーバーがポート ${port} で起動しました`);
});
こちらを入力したそのままのパスで以下のコードを実行(cmd)するとローカルサーバが立つ。
node server.js
Reactのデフォルトアプリを作成してちょっといじる
以下のコマンドを実行してwebアプリテンプレートを作成する。
npx create-react-app restaurant-app
実行完了してhappy hacking!が表示されるとrestaurant-appフォルダが作成されるので、そのフォルダのパスに移動。
また以下のコードも実行しておく。
npm install axios
axiosはAPIへのアクセスを行うモジュール?のようです。
あとは一応見た目を気にするということでtailwindをインストールして必要な記述をする。
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
@tailwind base;
@tailwind components;
@tailwind utilities;
最後にApp.jsを以下のソースで書き換える。
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [restaurants, setRestaurants] = useState([]);
const [name, setName] = useState('');
const [location, setLocation] = useState('');
const [cuisine, setCuisine] = useState('');
const [rating, setRating] = useState('');
const [searchQuery, setSearchQuery] = useState(''); // 検索クエリを追加
useEffect(() => {
axios.get('http://localhost:5000/api/restaurants')
.then((response) => {
setRestaurants(response.data.data);
})
.catch((error) => {
console.error("データの取得に失敗しました:", error);
});
}, []);
const addRestaurant = () => {
axios.post('http://localhost:5000/api/restaurants', {
name,
location,
cuisine,
rating: parseInt(rating),
})
.then((response) => {
setRestaurants([...restaurants, { id: response.data.id, name, location, cuisine, rating }]);
setName('');
setLocation('');
setCuisine('');
setRating('');
})
.catch((error) => {
console.error("レストランの追加に失敗しました:", error);
});
};
// 検索結果の絞り込み
const filteredRestaurants = restaurants.filter((restaurant) =>
restaurant.name.toLowerCase().includes(searchQuery.toLowerCase())
);
return (
<div className="min-h-screen bg-gray-100 p-8">
<h1 className="text-3xl font-bold text-center mb-8 text-blue-600">訪問した飲食店の管理</h1>
{/* 検索バー */}
<div className="max-w-md mx-auto mb-6">
<input
type="text"
placeholder="お店の名前で検索"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full p-2 border rounded-lg focus:outline-none focus:ring focus:ring-blue-300"
/>
</div>
<div className="max-w-md mx-auto bg-white shadow-md rounded-lg p-6 mb-8">
<h2 className="text-xl font-semibold mb-4 text-gray-700">新しい飲食店を追加</h2>
<input
type="text"
placeholder="店名"
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full mb-4 p-2 border rounded-lg focus:outline-none focus:ring focus:ring-blue-300"
/>
<input
type="text"
placeholder="場所"
value={location}
onChange={(e) => setLocation(e.target.value)}
className="w-full mb-4 p-2 border rounded-lg focus:outline-none focus:ring focus:ring-blue-300"
/>
<input
type="text"
placeholder="料理の種類"
value={cuisine}
onChange={(e) => setCuisine(e.target.value)}
className="w-full mb-4 p-2 border rounded-lg focus:outline-none focus:ring focus:ring-blue-300"
/>
<input
type="number"
placeholder="評価 (1〜5)"
value={rating}
onChange={(e) => setRating(e.target.value)}
className="w-full mb-4 p-2 border rounded-lg focus:outline-none focus:ring focus:ring-blue-300"
/>
<button
onClick={addRestaurant}
className="w-full bg-blue-500 text-white py-2 rounded-lg hover:bg-blue-600 transition"
>
追加
</button>
</div>
<h2 className="text-2xl font-semibold mb-4 text-gray-700 text-center">飲食店一覧</h2>
<ul className="max-w-md mx-auto space-y-4">
{filteredRestaurants.map((restaurant) => (
<li key={restaurant.id} className="bg-white shadow-md rounded-lg p-4">
<h3 className="text-lg font-semibold text-gray-800">{restaurant.name}</h3>
<p className="text-gray-600">場所: {restaurant.location}</p>
<p className="text-gray-600">料理の種類: {restaurant.cuisine}</p>
<p className="text-gray-600">評価: {restaurant.rating}</p>
</li>
))}
</ul>
</div>
);
}
export default App;
ここまで出来たら完成です。
C:\eval_restaurants\evaluate-app> npm start
npm startを実行するとアプリが立ち上がり、画面上で触ることができる。