概要
Next.jsにて動画をCloudinaryにアップロードして管理するアプリを作成したので、
どのように実装したかについて投稿します。
前準備編
Cloudinaryアカウント作成
まずはCloudinaryのアカウントを作成します
作成できたらクラウド名、APIキー、シークレットキーを控えておきます。
プレセット作成
Cloudinaryの設定画面で「Upload」→ 「Upload Presets」に移動して、
新しいプレセットを作成します。
Next.js側準備
以下コマンドでCloudinaryが定期用しているパッケージをインストールします。
$ npm install cloudinary
アップロード機能の実装方法
環境変数ファイル作成
.env.localファイルを作成して控えたクラウド名、APIキー、シークレットキーと作成したプレセット名を記載します。
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
CLOUDINARY_UPLOAD_PRESET=preset_name
実装する処理フロー
- クライアント側でユーザがアップロードファイルを指定する
- 指定されたファイルをアプリ側(サーバサイド)へ渡す
- サーバーサイド側でクライアント側から受信したファイルを取得
- サーバーサイド側で認証関連(APIキーなど)を使用してCloudinary APIを使用してアップロード
- 結果をクライアント側へ渡す
クライアント側実装方法
src/lib/cloudinary.tsを作成し、
実装する処理フロー1、2を実装します。
export const uploadVideo = async (file: File) => {
try {
const formData = new FormData();
formData.append('file', file); // ユーザのファイルを取得
const response = await fetch('/api/cloudinary', {
method: 'POST',
body: formData,
}); // サーバサイドの/api/cloudinaryへ送信
if (!response.ok) {
throw new Error('Failed to upload video');
}
const data = await response.json();
return {
url: data.secure_url,
publicId: data.public_id,
};
} catch (error) {
console.error('Error uploading video:', error);
throw error;
}
};
サーバーサイド側の実装
クライアント側から受け取るAPI(/api/cloudinary/route.tsx)を作成し、
処理フロー3、4、5を実装します。
import { NextResponse } from 'next/server';
import { v2 as cloudinary } from 'cloudinary';
// サーバー側でのみCloudinaryの設定を行う
cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
export async function POST(request: Request) {
try {
const formData = await request.formData();
const file = formData.get('file') as File;
if (!file) {
return NextResponse.json(
{ error: 'ファイルが指定されていません' },
{ status: 400 }
);
}
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
// サーバー側でCloudinaryのAPIを呼び出し
const result = await new Promise((resolve, reject) => {
cloudinary.uploader
.upload_stream(
{
resource_type: 'video',
},
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}
)
.end(buffer);
});
return NextResponse.json(result);
} catch (error) {
console.error('Cloudinary upload error:', error);
return NextResponse.json(
{ error: '動画のアップロードに失敗しました' },
{ status: 500 }
);
}
}
まとめ
クライアント側でファイル取得してサーバ側でアップロードを実装するというやり方は、
確かにセキュリティ上はそっちの方がいいよねって思いました。
学習の一環など実際に運用するわけではないから使えればいいやってなってたので、
今後何か作る時に認証周りがある場合はクライアント側、サーバー側で何をするかは
考えていく必要がありそうです。