Vercel でサーバーレス関数とMongoDB Atlasを使ってデプロイする方法 ～問題解決の備忘録～

本記事では、Vercel上でサーバーレス関数としてAPIを実装し、MongoDB Atlasを接続することでアプリケーションをデプロイするまでの流れと、実際に遭遇したエラーおよびその解決策をまとめています。  

## 目次

1. [実施したこと](#1-はじめに)
2. [具体的なエラーの説明](#2-具体的なエラーの説明)
3. [解決策の詳細](#3-解決策の詳細)
4. [デプロイ完了](#4-デプロイ完了と今後の展望)

---

## 1. はじめに

Vercelはサーバーレスプラットフォームであり、従来のExpressサーバーをそのままデプロイすることはできません。  
また、Vercel上ではローカルのMongoDB（`mongodb://localhost:XXXXX`）には接続できないため、クラウドサービスであるMongoDB Atlasを利用する必要があります。  
このプロジェクトでは、以下の3点を実施しました。

- **サーバーレス関数にすること**  
  ExpressベースのAPIコードを、Vercelの`api/`ディレクトリ内にサーバーレス関数として実装。

- **MongoDB Atlasの設定**  
  ローカルのMongoDBではなく、MongoDB Atlasにデータベースをホストし、接続URIを取得。  
  ※ 接続URIは安全に環境変数 `MONGO_URI` として管理。

- **Vercelの設定**  
  Vercelダッシュボードで環境変数の設定や、`vercel.json` を用いたルーティング設定を実施し、デプロイを行った。

---

## 2. 具体的なエラーの説明

デプロイおよび運用中に、いくつかのエラーに遭遇しました。以下に主なエラーとその内容を示します。

1. **接続URIが設定されていないエラー**  
   - **エラー内容**:  
     ```
     Error: MongoDBの接続URIが設定されていません。環境変数を確認してください。
     ```
   - **原因**:  
     環境変数 `MONGO_URI` の設定ミス。

2. **URI Malformed エラー**  
   - **エラー内容**:  
     ```
     MongoParseError: URI malformed
     ```
   - **原因**:  
     接続URI内のパスワードに含まれる特殊文字が正しくURLエンコードされていなかった。

3. **IPホワイトリストエラー**  
   - **エラー内容**:  
     ```
     MongooseServerSelectionError: Could not connect to any servers in your MongoDB Atlas cluster...
     ```
   - **原因**:  
     接続元のIPアドレスがMongoDB Atlasのホワイトリストに追加されていなかった。

4. **`db is not defined` エラー**  
   - **エラー内容**:  
     ```
     ReferenceError: db is not defined
     ```
   - **原因**:  
     `mongoose.connect()` の返り値を誤って参照していた。

5. **ドライバの deprecated オプション警告**  
   - **エラー内容**:  
     ```
     Warning: useNewUrlParser is a deprecated option...
     Warning: useUnifiedTopology is a deprecated option...
     ```
   - **原因**:  
     MongoDB Node.js ドライバ v4.x以降では、これらのオプションは不要になったため発生。

---

## 3. 解決策の詳細

それぞれのエラーに対して、以下の対応を行いました。

- **接続URIが設定されていないエラー**  
  → Vercelダッシュボードの「Environment Variables」で `MONGO_URI` を正しく設定し、再デプロイ。

- **URI Malformed エラー**  
  → 接続URI内のパスワード部分の特殊文字（例: `%`）を、URLエンコードして正しい形式に修正。

- **IPホワイトリストエラー**  
  → MongoDB Atlasの「Network Access」設定で `0.0.0.0/0` を許可し、全てのIPからの接続を許可。

- **`db is not defined` エラー**  
  → コード内で接続状態を確認する際に、`mongoose.connection` を正しく参照するよう修正。  
  例:  
  ```js
  isConnected = mongoose.connection.readyState === 1;

- **ドライバの deprecated オプション警告**
  → MongoDB Node.jsドライバv4.x以降では不要なため、useNewUrlParser と useUnifiedTopology オプションを削除。

## 4. デプロイ完了と今後の展望

これらの修正を適用した結果、Vercel上でサーバーレス関数として実装したAPIがMongoDB Atlasに接続でき、正常に動作するようになりました。  
具体的には、APIエンドポイント `/api/notes` に対してHTTP POSTリクエストを送ると、データがMongoDB Atlasに保存されるようになりました。

### 今後の注意点

- **環境変数の設定**:  
  デプロイ環境ごとに環境変数が正しく設定されているかを常に確認すること。

- **特殊文字のエンコード**:  
  接続URIに含まれるパスワードやその他の情報は、必ず正しいURLエンコードを行うこと。

- **IPホワイトリストの管理**:  
  MongoDB Atlasのアクセス設定を適切に管理し、必要なIPアドレスを許可すること。

- **ドライバやライブラリの更新**:  
  MongoDBドライバや関連ライブラリの変更点に注意し、警告やエラーが出た際は公式ドキュメントを参照して対応すること。

---

## まとめ

今回のプロジェクトでは、Vercelでサーバーレス関数を用い、MongoDB Atlasを接続するための以下の3点に注力しました。

1. **サーバーレス関数への移行**  
   - ExpressアプリケーションからAPI Routesへ変更し、`api/`ディレクトリに各エンドポイントを配置。

2. **MongoDB Atlasの設定**  
   - クラウド上のMongoDB Atlasを利用し、接続URIを環境変数 `MONGO_URI` として安全に管理。  
   - URIに含まれる特殊文字のエンコード、IPホワイトリストの設定などにも留意。

3. **Vercelの設定**  
   - Vercelダッシュボードで環境変数や`vercel.json`のルート設定、必要に応じたタイムアウト設定を行い、正常にデプロイ。  

また、デプロイ時に発生した各種エラー（接続URI未設定、URI malformed、IPホワイトリスト、db参照エラー、deprecatedオプション警告）について、その原因と解決策を実践し、無事に問題を解決することができました。  
これらの経験を通して、今後の開発やデプロイ作業がよりスムーズに進むと確信しています。

---

### 参考リンク

- [Vercel Documentation](https://vercel.com/docs)  
- [MongoDB Atlas Documentation](https://www.mongodb.com/cloud/atlas)  
- [Mongoose Documentation](https://mongoosejs.com/)

---

この記事が、VercelとMongoDB Atlasを活用したサーバーレスAPIの構築・デプロイにおける課題解決の参考になれば幸いです。