オタクくん「ギャル先輩!中規模WEBサービスを一人で立ち上げたいです!」
オタクくん「ギャル先輩!中規模WEBサービスを一人で立ち上げたいです!」
ギャル先輩「おっと、野心的だね〜。でも大丈夫、一人でもできるよ〜。まずは、何を作りたいかをちゃんと決めるところから始めよう!」
サービスのアイデアを固める
ギャル先輩「まず、どんなサービスを作りたいのかを明確にしようよ。具体的なアイデアはある?」
オタクくん「ユーザーが自分のタスクを管理できるToDoアプリを作りたいんです。でも、ただのToDoアプリじゃなくて、他のユーザーと共有したり、コメントしたりできる機能も欲しいんです。」
ギャル先輩「なるほど〜、じゃあ、次は技術スタックを決めようか!」
技術スタックの選定
オタクくん「技術スタックって何ですか?」
ギャル先輩「技術スタックっていうのは、サービスを作るために使う技術やツールのことだよ〜。例えば、フロントエンドにはReact、バックエンドにはNode.js、データベースにはMongoDBみたいな感じで決めていくんだよ。」
オタクくん「どうやって選べばいいんですか?」
ギャル先輩「それじゃ、オススメの技術スタックを教えるね〜」
- フロントエンド: React + Next.js
- バックエンド: Node.js + Express
- データベース: MongoDB
- ホスティング: Vercel (フロントエンド), Heroku (バックエンド)
- 認証: Firebase Authentication
プロジェクトのセットアップ
ギャル先輩「まず、フロントエンドのプロジェクトをセットアップしようか!」
オタクくん「どうやってやるんですか?」
ギャル先輩「こんな感じで、Next.jsのプロジェクトを作るよ〜」
npx create-next-app my-todo-app
cd my-todo-app
ギャル先輩「次に、バックエンドのプロジェクトをセットアップしよう!」
mkdir backend
cd backend
npm init -y
npm install express mongoose
基本的なAPIの作成
ギャル先輩「次は、バックエンドで基本的なAPIを作るよ〜。まずは、Expressを使って簡単なサーバーを立ち上げるね」
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const port = 3000;
app.use(express.json());
mongoose.connect('mongodb://localhost:27017/todo-app', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const todoSchema = new mongoose.Schema({
task: String,
completed: Boolean,
});
const Todo = mongoose.model('Todo', todoSchema);
app.get('/api/todos', async (req, res) => {
const todos = await Todo.find();
res.json(todos);
});
app.post('/api/todos', async (req, res) => {
const newTodo = new Todo({
task: req.body.task,
completed: false,
});
const savedTodo = await newTodo.save();
res.json(savedTodo);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
フロントエンドとバックエンドの連携
ギャル先輩「次は、フロントエンドからバックエンドのAPIを呼び出す部分を作るよ〜」
オタクくん「どうやってAPIを呼び出すんですか?」
ギャル先輩「こんな感じで、Next.jsのgetServerSideProps
を使ってデータをフェッチするんだよ〜」
// pages/index.js
import { useState } from 'react';
export default function Home({ initialTodos }) {
const [todos, setTodos] = useState(initialTodos);
const [task, setTask] = useState('');
const addTodo = async () => {
const res = await fetch('/api/todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ task }),
});
const newTodo = await res.json();
setTodos([...todos, newTodo]);
setTask('');
};
return (
<div>
<h1>ToDo App</h1>
<ul>
{todos.map((todo) => (
<li key={todo._id}>{todo.task}</li>
))}
</ul>
<input
type="text"
value={task}
onChange={(e) => setTask(e.target.value)}
/>
<button onClick={addTodo}>Add Todo</button>
</div>
);
}
export async function getServerSideProps() {
const res = await fetch('http://localhost:3000/api/todos');
const initialTodos = await res.json();
return {
props: {
initialTodos,
},
};
}
認証の追加
ギャル先輩「最後に、認証機能を追加しようか。Firebase Authenticationを使うと簡単だよ〜」
オタクくん「Firebase Authenticationって何ですか?」
ギャル先輩「Firebase Authenticationは、Googleが提供してる認証サービスで、簡単にユーザー認証を実装できるんだよ〜」
// pages/api/auth/[...nextauth].js
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
export default NextAuth({
providers: [
Providers.Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
database: process.env.DATABASE_URL,
});
まとめ
オタクくん「ギャル先輩、本当にありがとうございました!これで中規模WEBサービスを立ち上げる準備が整いました!」
ギャル先輩「よかったってばよ!」
Discussion