How to Implement File Upload with Claude Code
Learn how to implement file upload using Claude Code. Includes practical code examples and step-by-step guidance.
ファイルアップロード機能の実装にClaude Codeを使う
ファイルアップロードはバリデーション、署名付きURL、プログレス表示、画像リサイズなど実装項目が多い機能です。Claude Codeに一括して依頼することで、セキュアで使いやすいアップロード機能を効率的に構築できます。
署名付きURLによるダイレクトアップロード
> S3の署名付きURLを使ったファイルアップロードを実装して。
> サーバーを経由せず、クライアントから直接S3にアップロードする構成で。
> ファイルサイズは10MB以下、画像とPDFのみ許可して。
サーバーサイド(署名付きURL発行)
// src/app/api/upload/route.ts
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { NextRequest, NextResponse } from 'next/server';
import { nanoid } from 'nanoid';
const s3 = new S3Client({ region: 'us-east-1' });
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
const MAX_SIZE = 10 * 1024 * 1024; // 10MB
export async function POST(req: NextRequest) {
const { fileName, fileType, fileSize } = await req.json();
// バリデーション
if (!ALLOWED_TYPES.includes(fileType)) {
return NextResponse.json(
{ error: '許可されていないファイル形式です' },
{ status: 400 }
);
}
if (fileSize > MAX_SIZE) {
return NextResponse.json(
{ error: 'ファイルサイズは10MB以下にしてください' },
{ status: 400 }
);
}
const ext = fileName.split('.').pop();
const key = `uploads/${nanoid()}.${ext}`;
const command = new PutObjectCommand({
Bucket: process.env.S3_BUCKET!,
Key: key,
ContentType: fileType,
ContentLength: fileSize,
});
const signedUrl = await getSignedUrl(s3, command, { expiresIn: 300 });
return NextResponse.json({
uploadUrl: signedUrl,
fileUrl: `https://${process.env.S3_BUCKET}.s3.us-east-1.amazonaws.com/${key}`,
key,
});
}
クライアントサイド(プログレス付きアップロード)
import { useState, useCallback } from 'react';
interface UploadState {
progress: number;
uploading: boolean;
error: string | null;
fileUrl: string | null;
}
export function useFileUpload() {
const [state, setState] = useState<UploadState>({
progress: 0,
uploading: false,
error: null,
fileUrl: null,
});
const upload = useCallback(async (file: File) => {
setState({ progress: 0, uploading: true, error: null, fileUrl: null });
try {
// 1. 署名付きURLを取得
const res = await fetch('/api/upload', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
fileName: file.name,
fileType: file.type,
fileSize: file.size,
}),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(error);
}
const { uploadUrl, fileUrl } = await res.json();
// 2. S3に直接アップロード(プログレス付き)
await new Promise<void>((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
setState(prev => ({ ...prev, progress: Math.round((e.loaded / e.total) * 100) }));
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) resolve();
else reject(new Error('Upload failed'));
});
xhr.addEventListener('error', () => reject(new Error('Network error')));
xhr.open('PUT', uploadUrl);
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);
});
setState({ progress: 100, uploading: false, error: null, fileUrl });
return fileUrl;
} catch (err) {
setState(prev => ({
...prev,
uploading: false,
error: (err as Error).message,
}));
throw err;
}
}, []);
return { ...state, upload };
}
アップロードコンポーネント
function FileUploader() {
const { progress, uploading, error, fileUrl, upload } = useFileUpload();
const [dragOver, setDragOver] = useState(false);
const handleDrop = useCallback(async (e: React.DragEvent) => {
e.preventDefault();
setDragOver(false);
const file = e.dataTransfer.files[0];
if (file) await upload(file);
}, [upload]);
const handleFileSelect = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) await upload(file);
}, [upload]);
return (
<div>
<div
onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
onDragLeave={() => setDragOver(false)}
onDrop={handleDrop}
className={`border-2 border-dashed rounded-lg p-8 text-center transition-colors
${dragOver ? 'border-blue-500 bg-blue-50' : 'border-gray-300'}
${uploading ? 'pointer-events-none opacity-50' : 'cursor-pointer'}`}
>
<p className="text-gray-600">
ファイルをドラッグ&ドロップ、またはクリックして選択
</p>
<p className="mt-1 text-sm text-gray-400">
JPEG, PNG, WebP, PDF(10MB以下)
</p>
<input
type="file"
accept="image/jpeg,image/png,image/webp,application/pdf"
onChange={handleFileSelect}
className="hidden"
id="file-input"
/>
<label htmlFor="file-input" className="mt-4 inline-block cursor-pointer rounded bg-blue-600 px-4 py-2 text-white">
ファイルを選択
</label>
</div>
{uploading && (
<div className="mt-4">
<div className="h-2 rounded-full bg-gray-200">
<div
className="h-full rounded-full bg-blue-600 transition-all"
style={{ width: `${progress}%` }}
/>
</div>
<p className="mt-1 text-sm text-gray-500">{progress}%</p>
</div>
)}
{error && <p className="mt-2 text-sm text-red-600">{error}</p>}
{fileUrl && (
<p className="mt-2 text-sm text-green-600">
アップロード完了
</p>
)}
</div>
);
}
画像リサイズの処理
アップロードされた画像をLambdaで自動リサイズする処理もClaude Codeに依頼できます。
// lambda/resize-image.ts
import { S3Event } from 'aws-lambda';
import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
import sharp from 'sharp';
const s3 = new S3Client({});
const SIZES = [
{ suffix: 'thumb', width: 200, height: 200 },
{ suffix: 'medium', width: 800 },
{ suffix: 'large', width: 1600 },
];
export async function handler(event: S3Event) {
for (const record of event.Records) {
const bucket = record.s3.bucket.name;
const key = decodeURIComponent(record.s3.object.key);
const { Body } = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
const buffer = Buffer.from(await Body!.transformToByteArray());
for (const size of SIZES) {
const resized = await sharp(buffer)
.resize(size.width, size.height, { fit: 'cover' })
.webp({ quality: 80 })
.toBuffer();
const resizedKey = key.replace(/\.[^.]+$/, `-${size.suffix}.webp`);
await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: resizedKey,
Body: resized,
ContentType: 'image/webp',
}));
}
}
}
Zusammenfassung
Claude Codeを使えば、ファイルアップロード機能を署名付きURL、プログレス表示、バリデーション、画像リサイズまで含めて効率的に実装できます。セキュリティを考慮した実装を一括で生成できるのが強みです。AWS連携の詳細はAWSデプロイの自動化も参照してください。個人プロジェクトでの活用法は個人開発を爆速にする方法で紹介しています。
Claude Codeの詳細はAnthropic公式ドキュメントをご覧ください。
Related Posts
So beschleunigen Sie Ihre Nebenprojekte mit Claude Code [Mit Beispielen]
Erfahren Sie, wie Sie persönliche Entwicklungsprojekte mit Claude Code drastisch beschleunigen. Inklusive realer Beispiele und eines praktischen Workflows von der Idee bis zum Deployment.
So automatisieren Sie Refactoring mit Claude Code
Erfahren Sie, wie Sie Code-Refactoring mit Claude Code effizient automatisieren. Inklusive praktischer Prompts und konkreter Refactoring-Muster für reale Projekte.
Vollständiger CORS-Konfigurationsleitfaden mit Claude Code
Erfahren Sie alles über die CORS-Konfiguration mit Claude Code. Mit praktischen Tipps und Codebeispielen.