Skip to content

Instantly share code, notes, and snippets.

@mateosantosdev
Last active September 22, 2023 19:39
Show Gist options
  • Save mateosantosdev/9a1acb802ddcafb31f16b1cd047e6c5b to your computer and use it in GitHub Desktop.
Save mateosantosdev/9a1acb802ddcafb31f16b1cd047e6c5b to your computer and use it in GitHub Desktop.
Upload file to S3 with RemixJS
import { json, type ActionFunctionArgs } from '@remix-run/node';
import { requireUserId } from '~/utils/session.server';
import { uploadAvatar } from '~/utils/upload.server';
import { badRequest } from '~/utils/utils';
export async function action({ request }: ActionFunctionArgs) {
const userId = await requireUserId(request);
const formData = await request.formData();
try {
const id = formData.get('id')?.toString();
if (!id) throw new Error('Id is required');
const avatar = formData.get('photo') as File;
if (avatar.size === 0) throw new Error('File is required');
const uploadedImageName = await uploadAvatar(avatar);
return json({ error: false, ok: true, image: uploadedImageName });
} catch (error: any) {
return badRequest({
uploadError: error.message || 'Unknown error'
});
}
}
import { fileTypeFromBuffer } from 'file-type';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { createId } from '@paralleldrive/cuid2';
const s3 = new S3Client({
region: 'eu-west-1',
credentials: {
accessKeyId: process.env.S3_AWS_KEY || '',
secretAccessKey: process.env.S3_AWS_SECRET || ''
}
});
export async function uploadAvatar(file: File) {
const imageName = `${createId()}.${file.name.split('.').slice(-1)}`;
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const mime = await fileTypeFromBuffer(buffer);
const uploadToS3Command = new PutObjectCommand({
Bucket: process.env.S3_BUCKET_NAME || '',
Key: imageName,
Body: buffer,
ACL: 'public-read',
ContentType: mime?.mime
});
await s3.send(uploadToS3Command);
return imageName;
}
<fetcher.Form
method="post"
encType="multipart/form-data"
action="/api/upload-photo"
>
<input type="hidden" name="id" value="the user id" />
<input type="file" name="photo" id="photo" accept="image/*" />
<button
type="submit"
disabled={fetcher.state !== 'idle'}
>
{fetcher.state === 'idle' ? 'Submit' : 'Loading...'}
</button>
</fetcher.Form>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment