Basics / Body Parsing
File Uploads
Archery makes inspecting and saving uploaded files extremely straightforward. The framework automatically parses multipart/form-data requests and exposes file data through robust UploadedFile objects.
Retrieving Uploaded Files
You can access files submitted via a form request using the file method on the FormRequest wrapper.
router.post('/avatar/upload', (request) async {
final form = request.form();
final avatar = await form.file('avatar');
if (avatar == null || !avatar.isValid) {
request.flash(key: 'error', message: 'Please provide a valid file.');
return request.redirectBack();
}
});
To retrieve an array containing all uploaded files, use await form.files().
Inspecting the File
The UploadedFile object contains various helpers for inspecting the file’s properties before you decide to persist it.
// The original name of the file
final String name = avatar.filename;
// The file extension (e.g., 'png')
final String extension = avatar.extension;
// Pre-flight checks for media types
final bool isImage = avatar.isImage;
final bool isVideo = avatar.isVideo;
final bool isAudio = avatar.isAudio;
// Get the actual size in bytes
final int sizeInBytes = await avatar.length;
Storing Files Locally
You can persist the UploadedFile directly to a specific disk location, or use the framework's convenience paths.
Private & Public Disk Contexts
Archery exposes helper methods to save your uploads securely.
// Saves with an auto-generated UUID to lib/src/storage/private/documents/
await document.saveToPrivateDir('documents');
// Saves with an auto-generated UUID to lib/src/http/public/avatars/
await avatar.saveToPublicDir('avatars');
If you prefer to keep the original filename instead of generating a UUID, pass autoName: false:
await document.saveToPrivateDir('documents', autoName: false);
Absolute Path
If you need to define the absolute directory path, simply pass it to the .save() method:
await avatar.save('/var/www/uploads/custom_name.png');
Storing Files on Amazon S3
Archery includes native S3 abstractions. UploadedFile can seamlessly stream its byte payload directly to your S3 bucket without forcing large files into expensive temporary disk I/O.
final objectKey = await avatar.streamToS3(
acl: S3Acl.publicRead,
autoName: true
);
if (objectKey != null) {
print('Uploaded to S3: $objectKey');
}
Note: You must have your AWS environment variables configured properly to leverage this feature. Review the AWS Integration section for setup details.
File Properties & Streaming
For lower-level use cases, you can access the raw bytes, interpret the text buffer, or stream it to another destination.
// Read text files easily
final content = await textFile.string;
// Get raw Uint8List buffer
final bytes = await avatar.bytes;
// Stream to a custom StreamSink
final controller = StreamController<List<int>>();
await avatar.streamTo(controller.sink);
You can even stream a file directly to the HTTP response, which is incredibly useful for delivering media equipped with Accept-Ranges support for quick scrubbing in the browser:
router.get('/video/stream', (request) async {
final videoFile = await retrieveStoredFile();
await videoFile.streamToResponse(request);
});