はじめに
近年、クラウドデータベースと型安全なプログラミング言語を活用したWebアプリケーション開発が注目を集めています。特に、MongoDB Atlasは手軽にデータベースをクラウドで管理でき、スケーラブルなアプリケーション構築に適しています。また、TypeScriptはコードの可読性と保守性を高めるため、多くの開発者に採用されています。
本記事では、これらの技術を組み合わせて、REST APIを構築する方法を具体的に解説します。MongoDB AtlasのセットアップからExpressを使ったルーティング、TypeScriptを用いた型安全な実装方法まで、初心者の方にも分かりやすいステップバイステップ形式で進めていきます。この記事を読むことで、MongoDB Atlasを活用したAPI開発の基礎を身につけるとともに、型安全な開発手法の利点を実感していただけるでしょう。
Express
の仕組みがまだあまり詳しくないという方向けにExpress
の基本的な使い方を解説した記事をご用意しています。
MongoDBとは
MongoDBは、ドキュメント指向のNoSQLデータベースで、柔軟なデータモデルやスケーラビリティに優れたデータベース管理システムです。以下の特徴を持っています:
主な特徴
-
ドキュメント指向
データはJSON形式に似た「BSON(Binary JSON)」として保存されます。テーブルや行(RDBMS)ではなく、コレクション(Collection)とドキュメント(Document)という概念を用います。 -
スキーマレス
明確なスキーマ定義が不要で、データ構造を柔軟に変更可能。プロジェクトの要件変更やスケールアップに強い。 -
高いスケーラビリティ
シャーディング(データの分割)により、水平スケーリングが簡単。大量のデータを効率よく処理可能。 -
高性能
高速な読み書き性能。特にリアルタイムデータの分析や、頻繁にデータ構造が変わるアプリケーションに最適。 -
豊富なエコシステム
Node.js、Python、Javaなどの主要なプログラミング言語用ドライバを提供。MongoDB Atlas(クラウドサービス)を使えば、インフラ構築なしでデータベースを利用可能。
MongoDB Atlasとは
MongoDB Atlasは、MongoDB社が提供するクラウドベースのデータベースサービスです。手間のかかるサーバー構築や運用管理を代行してくれるフルマネージド型のデータベースプラットフォームで、以下のクラウドプロバイダーで利用できます:
- AWS(Amazon Web Services)
- GCP(Google Cloud Platform)
- Microsoft Azure
ローカル環境でDockerを起動してMongoDBをセットアップする選択肢もありますがより簡単に始められるということで今回はMongoDB Atlasを使っていきます。
MongoDB Atlasはストレージが512MBまでであれば無料で使えます。
mongoDB Atlasの設定
こちらからアクセスしてアカウント登録を行います。
New Project
で新規プロジェクト作成画面へ
プロジェクト名はexpress-tutorial
とします。
Create Project
でプロジェクトを作成します。
プロジェクトの作成が完了しましたので次はクラスターの作成を行います。
クラスターのスペックを選択できます。
今回はFree
となっているM0
を選択し、クラスターを作成します。
クラスターに接続するIPアドレスとユーザーを設定します。
IPアドレスについては一旦current IP Address
でいいかと思います。Express
をどこかにデプロイする際には設定を変える必要が出てきます。
後はユーザーとパスワードを設定します。
設定が完了するとChoose a connection method
で
Drivers
を選択
Mongoose
を選択
環境変数に設定する必要があるためメモしておきます。
mongodb+srv://dbUser:<db_password>@cluster0.elo46.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0
プロジェクトのセットアップ
Express
用のプロジェクトを新規作成し必要なパッケージをインストールします。
mkdir express-mongodb-rest-api-development-with-typescript
cd express-mongodb-rest-api-development-with-typescript
npm init -y
パッケージのインストール
npm i express cors dotenv express-async-handler mongoose
npm i -D @types/node @types/express @types/mongoose @types/cors rimraf @types/rimraf ts-node-dev typescript
express
- 用途: Node.js のウェブフレームワーク。
- 役割:
- ルーティング(HTTPリクエストの処理を分岐)。
- ミドルウェアを使ったリクエスト/レスポンスの処理。
- REST APIやWebアプリケーションの構築に便利。
@types/express
- 用途: Expressの型定義ファイル。
- 役割:
- TypeScriptでExpressを型安全に使用可能にする。
- ルートやミドルウェアの引数・戻り値の型を明確化。
cors
- 用途: クロスオリジンリソース共有(CORS)を設定するミドルウェア。
- 役割:
- 他のオリジン(ドメイン)からのリクエストを許可。
- フロントエンドとバックエンドの安全な連携を実現。
@types/cors
- 用途: CORSの型定義ファイル。
- 役割:
- TypeScriptでCORSミドルウェアを型安全に使用可能にする。
- 設定オプションの型を明示。
dotenv
- 用途:
.env
ファイルから環境変数を読み込むパッケージ。 - 役割:
- 環境変数(APIキーやデータベースURLなど)を安全に管理。
- 環境ごとの設定切り替えを簡素化。
express-async-handler
- 用途: Expressの非同期関数を簡単に扱うためのユーティリティ。
- 役割:
- 非同期関数内のエラー処理を簡素化。
try-catch
を書かずにエラーハンドラーにエラーを渡す。
mongoose
- 用途: MongoDB用のオブジェクトデータモデリング(ODM)ライブラリ。
- 役割:
- スキーマやモデルを定義。
- MongoDBとのクエリを簡素化。
- ドキュメントとJavaScriptオブジェクトのマッピングを提供。
@types/mongoose
- 用途: Mongooseの型定義ファイル。
- 役割:
- TypeScriptでMongooseを型安全に使用可能にする。
- モデルやスキーマの型定義を強化。
@types/node
- 用途: Node.jsの型定義ファイル。
- 役割:
- TypeScriptでNode.jsの組み込みモジュール(fs, http, pathなど)を型安全に使用可能にする。
rimraf
- 用途: フォルダやファイルを削除するためのユーティリティ。
- 役割:
- クロスプラットフォームで
rm -rf
のような操作を実現。
- クロスプラットフォームで
@types/rimraf
- 用途: rimrafの型定義ファイル。
- 役割:
- TypeScriptでrimrafを型安全に使用可能にする。
ts-node
- 用途: TypeScriptコードを直接実行するためのツール。
- 役割:
- トランスパイルせずにTypeScriptのスクリプトを実行。
- 開発中に便利。
ts-node-dev
- 用途: TypeScriptコードのホットリロード用ツール。
- 役割:
- コード変更時にサーバーを自動再起動。
- 開発の効率化。
tsconfigの作成
TypeScript プロジェクトのコンパイラ設定を管理するためのtsconfig.json
ファイルを作成します。
npx tsc --init
.envの作成
先ほど取得したMongoDBへの接続情報を.env
で管理します。
MONGO_URI=mongodb+srv://dbUser:dbUserPassword@cluster0.elo46.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0
ExpressからMongoDBへの接続
MongoDBへの接続処理
src/lib/db.ts
ファイルを作成しコードを書いていきます。
import mongoose from 'mongoose';
import dotenv from 'dotenv';
dotenv.config();
const DATABASE_URL = process.env.MONGO_URI!
const connectDB = async () => {
try {
const connection = await mongoose.connect(DATABASE_URL);
console.log(`MongoDB Connected ${connection.connection.host}`);
} catch (error) {
if (error instanceof Error) {
console.error(`Error: ${error.message}`);
} else {
console.error(`Unexpected Error: ${error}`);
}
process.exit(1);
}
};
export default connectDB;
Express
のエントリポイント作成
import express from 'express';
import cors from 'cors';
import connectDB from './lib/db';
connectDB();
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.listen(3001);
console.log('Express WebAPI listening on port ' + port);
package.jsonの設定
Expressサーバーを起動するためのコマンドをpackage.json
に設定します。
"scripts": {
+ "dev": "ts-node-dev --respawn src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
動作確認
下記のコマンドでExpressサーバの起動とMongoDBへの接続を行います。
npm run dev
下記のようなメッセージが表示されましたらどちらも成功となります。
Modelの作成
MongoDBにデータを格納するためのデータの定義を行っていきます。
今回はTODOアプリを作成する想定で以下の項目を用意します。
- タイトル:String
- 完了フラグ:Boolean (初期値:false)
- 作成日:Date (初期値:登録日時)
- 更新日:Date
import mongoose from 'mongoose';
const PostSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
isCompleted: {
type: Boolean,
required: true,
default: false,
},
createdAt: {
type: Date,
required: true,
default: Date.now,
},
updatedAt: {
type: Date,
},
},
);
const Post = mongoose.model('Post', PostSchema);
export default Post;
データの登録
先ほど作成したモデルを使って初期データをローカル環境からMongoDBへ登録します。
登録用のデータ作成
2件todoを作成します。
isCompleted
、createdAt
についてはデフォルト値を設定しているためここでは省略しています。
export const todos = [
{
title: '問い合わせに返信する',
},
{
title: 'ブログを作成する',
},
]
登録処理スクリプトの作成
登録する処理についてはやり直しが効くように一度全件削除してから登録します。
また全件削除ができる処理も事前に用意しています。
import dotenv from 'dotenv';
import { todos } from './todo';
import Todo from '../models/todo';
import connectDB from '../lib/db';
dotenv.config();
connectDB();
const importData = async () => {
try {
// todoを一旦削除してから全件登録
await Todo.deleteMany();
const createPosts = await Todo.insertMany(todos);
console.log(`Data Imported!`);
process.exit();
} catch (error) {
console.error(`Error: ${error}`);
process.exit(1);
}
};
const destroyData = async () => {
try {
await Todo.deleteMany();
console.log(`Data Destroyed!`);
process.exit();
} catch (error) {
console.error(`Error: ${error}`);
process.exit(1);
}
};
// コマンドラインでパラメータ -d を渡すと削除モードにする
if (process.argv[2] === '-d') {
destroyData();
} else {
importData();
}
データの登録
下記コマンドでデータの登録を行います。
npx ts-node src/seeds/seed.ts
Data Imported!
と表示されれば登録完了です。
MongoDB Atlas上でも登録されたことを確認できます。
一通りの準備ができましたのでここから実装に入っていきます。
データの参照(GETメソッド)
まずは登録済みのデータを参照するGETメソッドを実装します。
コントローラーの作成
コントローラーにDBアクセスの処理を作成します。
import {Request, Response} from 'express';
import asyncHandler from 'express-async-handler';
import Todo from '../models/todo';
export const getPosts = asyncHandler(async (req: Request, res: Response) => {
const todos = await Todo.find();
res.json(todos);
});
ルーティングの作成
GETメソッドでアクセスが来た場合に先ほどのgetTodos
を呼び出すよう定義します。
またこの後、POSTメソッドなど他のルートも作成するためグループ化しておきます。
import express from 'express';
import { getTodos } from '../controllers/todo';
const router = express.Router();
router.route('/').get(getTodos)
export default router
エントリポイントにルーティングの反映
上記内容をエントリーポイントに反映させます。
今回のTODOアプリのURLは/todos
配下に全て設定されます。
import express from 'express';
import cors from 'cors';
import connectDB from './lib/db';
+ import todoRoutes from './routes/todo'
connectDB();
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
+ app.use('/todos', todoRoutes)
app.listen(3001);
console.log('Express WebAPI listening on port 3001');
Express
のルーティングについては下記の記事で詳しく説明してあります。
動作確認
実際にAPIにアクセスしてデータが参照できるか確認します。
出力結果を見やすくするためにjq
を使用しています。
curl -s http://localhost:3001/todos | jq
事前に登録した2件のtodoが出力されればOKです。
データの新規登録(POSTメソッド)
GETメソッドと実装の仕方はほぼ同じです。
export const addTodo = asyncHandler(async (req: express.Request, res: express.Response) => {
const newPost = new Post(req.body as PostType);
await newPost.save((error, post) => {
if (error) res.send(error);
res.json(post);
});
});
POSTメソッドのアクセスURLはGETメソッドと同じものを使用します。
- router.route('/').get(getTodos)
+ router.route('/').get(getTodos).post(addTodo)
動作確認
POSTメソッドでリクエストを送信します。
curl -X POST -H "Content-Type: application/json" -d '{"title": "投稿テスト"}' http://localhost:3001/todos
正常に登録されますと登録内容が返却されます。
データの更新(PATCHメソッド)
受け取ったtodoId
を元に対象のデータを探して更新します。
id
が存在せず更新できなかった場合はその旨をメッセージとして返します。
export const updateTodo = asyncHandler(async (req: Request, res: Response): Promise<void> => {
const todo = await Todo.findByIdAndUpdate(
{ _id: req.params.todoId },
req.body,
{ new: true }
);
if (!todo) {
res.status(404).json({ message: "Todo not found" });
}
res.json(todo)
});
todoId
を受け取れるようルーティングを定義します。
router.route('/:todoId').patch(updateTodo)
動作確認
今回は登録済みのTodoに対して完了したフラグをつけてみます。
更新対象のTodoはコチラにします。
[
{
"_id": "678064b4923d0c1c0e9ebea6",
"title": "問い合わせに返信する",
"isCompleted": false,
"createdAt": "2025-01-10T00:07:16.292Z",
"__v": 0
},
{"isCompleted": true}
をPATCHメソッドのbodyにセット。
更新対象のIDはURLにセットします。
curl -X PATCH -H "Content-Type: application/json" -d '{"isCompleted": true}' http://localhost:3001/todos/678064b4923d0c1c0e9ebea6
更新結果でisCompleted: true
となったことを確認できました。
id
を678064b4923d0c1c0e9ebea5
と、一番最後の数字を変更し存在しないidにした状態でリクエストを送ると、設定したメッセージが返ってくることが確認できます。
データの削除(DELETEメソッド)
受け取ったtodoId
を元に対象のデータを探して削除します。
id
が存在せず削除できなかった場合はその旨をメッセージとして返します。
export const deleteTodo = asyncHandler(async (req: Request, res: Response): Promise<void> => {
const todo = await Todo.findByIdAndDelete(req.params.todoId);
if (!todo) {
res.status(404).json({ message: "Todo not found" });
}
res.json({ message: "Todo deleted successfully", todo });
});
DELETEメソッドもtodoId
を受け取れるようルーティングを定義します。
- router.route('/:todoId').patch(updateTodo)
+ router.route('/:todoId').patch(updateTodo).delete(deleteTodo)
動作確認
こちらのデータを削除します。
{
"_id": "6780847655833897d0f2f103",
"title": "投稿テスト",
"isCompleted": false,
"createdAt": "2025-01-10T02:22:46.525Z",
"__v": 0
}
]
下記のコマンドでDELETEメソッドのリクエストを送信します。
curl -X DELETE http://localhost:3001/todos/6780847655833897d0f2f103
正常に削除されることが確認できるかと思います。
一度実行した後に再度同じリクエストを送信すると既に存在しないid
となっているため削除できない旨のメッセージが表示されます。
さいごに
本記事では、MongoDB Atlasを活用したREST APIの構築方法について、初期設定から実装、そして型安全な開発のポイントまでを解説しました。これを通じて、MongoDB AtlasとTypeScriptの基本的な活用方法をご理解いただけたのではないでしょうか。
これからアプリケーションをさらに拡張する際には、認証機能や高度なエラーハンドリング、そしてデプロイ環境の整備なども視野に入れることで、より実用的で信頼性の高いAPIを作成できます。また、TypeScriptの型付けを強化することで、チーム開発や長期的なプロジェクトにおけるメンテナンス性も向上します。
MongoDB AtlasとTypeScriptを活用しプロジェクトが成功することを応援しています。
おすすめ記事
Supertest と Jest を組み合わせて Express アプリケーションの API テストを効率化する方法を解説します。
サービス層の導入やテスト可能なコード設計へのリファクタリング、GET, POST, PATCH, DELETEメソッドのテスト実装まで、具体的なコード例を交えて詳しく紹介します。
関連記事
- Supertest と Jest を活用した Express + MongoDB アプリのエンドツーエンドテスト解説
2024/12/20 - TypeScriptで始めるApollo Server入門:Express & MongoDB連携ガイド
2024/12/25 - Express(+TypeScript)入門ガイド: Webアプリケーションを素早く構築する方法
2024/12/07 - フロントエンド開発に役立つモックサーバー構築:@graphql-tools/mock と Faker を使った実践ガイド
2024/12/25 - JestとTypeScriptで始めるテスト自動化:基本設定から型安全なテストの書き方まで徹底解説
2023/09/13 - Next.jsとAuth.jsで認証機能を実装するチュートリアル
2024/09/13 - 【Next.js】フロントエンド開発で欠かせないReactのUIコンポーネントのテストをReact Testing Libraryで実装
2023/09/20 - React + TypeScript + Webpackでバンドル環境を作るステップバイステップガイド
2025/01/05