api-upload
@rtorcato/api-upload uploads a single file from a multipart Express request
straight to S3 (via multer-s3) and
resolves with the stored object. ACL, cache-control, and deterministic keys are
configurable, and failures come back as api-errors HttpErrors
so they slot into the error handler.
Install
pnpm add @rtorcato/api-upload @aws-sdk/client-s3 multer multer-s3 express
@aws-sdk/client-s3, multer, multer-s3, and express are peer dependencies —
you bring your own versions and S3 client.
Usage
import { S3Client } from '@aws-sdk/client-s3'
import { uploadFile } from '@rtorcato/api-upload'
const s3 = new S3Client({ region: 'us-east-1' })
app.post('/avatar', async (req, res, next) => {
try {
const file = await uploadFile(req, res, {
s3,
bucket: 'avatars',
field: 'avatar',
key: `users/${req.user.id}.png`,
isPublic: true,
maxSizeBytes: 5 * 1024 * 1024,
})
res.json({ url: file.location })
} catch (err) {
next(err)
}
})
key can be a string or a function (req, file) => string.
Errors
uploadFile rejects with an HttpError:
413 file_too_large— requestContent-LengthexceedsmaxSizeBytes(checked before anything streams to S3).400 no_file— the field was empty.400— any other multer error (e.g. unexpected field).
Notes
- ACL —
isPublicsetspublic-read/private. Buckets with Object Ownership bucket-owner-enforced reject ACLs; leaveisPublicunset and use a bucket policy instead. - Size limit — enforced via
Content-Lengthup front (includes small multipart overhead), which avoids buffering oversized bodies and a multer-s3 hang when aborting an in-flight upload on multer's own limit.
Related
- api-errors — the
HttpErrorclasses failures are normalized to