Managing Binary Files with RESTHeart
🔧 Configuration
RESTHeart provides full support for storing and retrieving binary files of any size in MongoDB. This functionality uses MongoDB’s GridFS, which stores files that exceed the BSON document size limit of 16MB.
Tip
|
GridFS automatically splits large files into smaller chunks and stores them in separate documents. |
File Buckets
What is a File Bucket?
A file bucket is a special collection designed for storing binary files along with their metadata. In MongoDB terms, it’s a GridFS bucket.
Important
|
File bucket names must end with .files (e.g., images.files is a valid file bucket name)
|
Creating a File Bucket
To store binary files, first create a file bucket:
cURL
curl -i -X PUT [INSTANCE-URL]/mybucket.files \
-H "Authorization: Basic [BASIC-AUTH]"
HTTPie
http PUT [INSTANCE-URL]/mybucket.files \
Authorization:"Basic [BASIC-AUTH]"
JavaScript
fetch('[INSTANCE-URL]/mybucket.files', {
method: 'PUT',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => {
if (response.ok) {
console.log('File bucket created successfully');
} else {
console.error('Failed to create file bucket:', response.status);
}
})
.catch(error => console.error('Error:', error));
Uploading Files
POST - Upload a New File
To upload a file, use a POST
request with multipart/form-data
encoding:
cURL
curl -i -X POST [INSTANCE-URL]/mybucket.files \
-H "Authorization: Basic [BASIC-AUTH]" \
-F "file=@/path/to/example.jpg" \
-F 'metadata={"author":"SoftInstigate","category":"documentation"}'
HTTPie
http --form POST [INSTANCE-URL]/mybucket.files \
Authorization:"Basic [BASIC-AUTH]" \
file@/path/to/example.jpg \
metadata='{"author":"SoftInstigate","category":"documentation"}'
JavaScript
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('metadata', JSON.stringify({
"author": "SoftInstigate",
"category": "documentation"
}));
fetch('[INSTANCE-URL]/mybucket.files', {
method: 'POST',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
},
body: formData
})
.then(response => {
if (response.ok) {
console.log('File uploaded successfully');
return response.headers.get('Location');
} else {
console.error('Failed to upload file:', response.status);
}
})
.then(location => {
if (location) console.log('File location:', location);
})
.catch(error => console.error('Error:', error));
The request has two parts:
* file
: The binary content of the file
* metadata
: A JSON object with custom metadata (optional)
HTTP/1.1 201 Created
Location: [INSTANCE-URL]/mybucket.files/60f8a7b9e4b053f542c13ece
The Location
header contains the URI of the newly created file, with the automatically generated ID.
PUT - Upload with a Custom ID
To upload a file with a specific ID, use a PUT
request:
cURL
curl -i -X PUT [INSTANCE-URL]/mybucket.files/my-custom-id \
-H "Authorization: Basic [BASIC-AUTH]" \
-F "file=@/path/to/example.jpg" \
-F 'metadata={"author":"SoftInstigate","category":"documentation"}'
HTTPie
http --form PUT [INSTANCE-URL]/mybucket.files/my-custom-id \
Authorization:"Basic [BASIC-AUTH]" \
file@/path/to/example.jpg \
metadata='{"author":"SoftInstigate","category":"documentation"}'
JavaScript
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('metadata', JSON.stringify({
"author": "SoftInstigate",
"category": "documentation"
}));
fetch('[INSTANCE-URL]/mybucket.files/my-custom-id', {
method: 'PUT',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
},
body: formData
})
.then(response => {
if (response.ok) {
console.log('File uploaded successfully with custom ID');
} else {
console.error('Failed to upload file:', response.status);
}
})
.catch(error => console.error('Error:', error));
Retrieving Files
GET - File Metadata
To retrieve a file’s metadata:
cURL
curl -i -X GET [INSTANCE-URL]/mybucket.files/my-custom-id \
-H "Authorization: Basic [BASIC-AUTH]"
HTTPie
http GET [INSTANCE-URL]/mybucket.files/my-custom-id \
Authorization:"Basic [BASIC-AUTH]"
JavaScript
fetch('[INSTANCE-URL]/mybucket.files/my-custom-id', {
method: 'GET',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => response.json())
.then(data => {
console.log('Retrieved file metadata:', data);
})
.catch(error => console.error('Error:', error));
HTTP/1.1 200 OK
Content-Type: application/json
{
"_id": "my-custom-id",
"chunkSize": 261120,
"filename": "example.jpg",
"length": 66273,
"metadata": {
"_etag": {
"$oid": "60f8a7b9e4b053f542c13ecd"
},
"author": "SoftInstigate",
"category": "documentation",
"contentType": "image/jpeg"
},
"uploadDate": {
"$date": 1626955705283
}
}
The response includes:
-
_id
: The file identifier -
chunkSize
: The size of each chunk in bytes -
filename
: The original filename -
length
: Total file size in bytes -
metadata
: Custom metadata plus system-generated fields -
uploadDate
: When the file was uploaded
GET - File Binary Content
To retrieve the actual binary file:
GET [INSTANCE-URL]/mybucket.files/my-custom-id/binary HTTP/1.1
Authorization: Basic [BASIC-AUTH]
curl -i -X GET [INSTANCE-URL]/mybucket.files/my-custom-id/binary \
-H "Authorization: Basic [BASIC-AUTH]"
http GET [INSTANCE-URL]/mybucket.files/my-custom-id/binary \
Authorization:"Basic [BASIC-AUTH]"
fetch('[INSTANCE-URL]/mybucket.files/my-custom-id/binary', {
method: 'GET',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => response.blob())
.then(blob => {
console.log('Retrieved binary file:', blob);
// Process the binary data as needed
})
.catch(error => console.error('Error:', error));
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 66273
(binary data)
RESTHeart automatically sets the appropriate Content-Type
header based on the detected file type.
Filtering Files by Metadata
You can query files by their metadata just like regular documents:
cURL
curl -i -X GET "[INSTANCE-URL]/mybucket.files" \
-H "Authorization: Basic [BASIC-AUTH]" \
--data-urlencode 'filter={"metadata.author":"SoftInstigate"}'
HTTPie
http GET [INSTANCE-URL]/mybucket.files \
Authorization:"Basic [BASIC-AUTH]" \
filter=='{\'metadata.author\':"SoftInstigate"}'
JavaScript
const filter = encodeURIComponent(JSON.stringify({"metadata.author":"SoftInstigate"}));
fetch(`[INSTANCE-URL]/mybucket.files?filter=${filter}`, {
method: 'GET',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => response.json())
.then(data => {
console.log('Filtered files:', data);
})
.catch(error => console.error('Error:', error));
This returns metadata for all files with the specified author.
Updating File Metadata
PATCH - Update Specific Metadata Fields
To update specific metadata fields:
cURL
curl -i -X PATCH [INSTANCE-URL]/mybucket.files/my-custom-id \
-H "Authorization: Basic [BASIC-AUTH]" \
-H "Content-Type: application/json" \
-d '{
"metadata.category": "images",
"metadata.tags": ["example", "documentation"]
}'
HTTPie
http PATCH [INSTANCE-URL]/mybucket.files/my-custom-id \
Authorization:"Basic [BASIC-AUTH]" \
Content-Type:application/json \
metadata.category="images" \
metadata.tags:='["example", "documentation"]'
JavaScript
fetch('[INSTANCE-URL]/mybucket.files/my-custom-id', {
method: 'PATCH',
headers: {
'Authorization': 'Basic [BASIC-AUTH]',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"metadata.category": "images",
"metadata.tags": ["example", "documentation"]
})
})
.then(response => {
if (response.ok) {
console.log('File metadata updated successfully');
} else {
console.error('Failed to update file metadata:', response.status);
}
})
.catch(error => console.error('Error:', error));
Important
|
When updating metadata, use Content-Type: application/json , not multipart/form-data.
|
PUT - Replace All Metadata
To completely replace the metadata:
cURL
curl -i -X PUT [INSTANCE-URL]/mybucket.files/my-custom-id \
-H "Authorization: Basic [BASIC-AUTH]" \
-H "Content-Type: application/json" \
-d '{
"metadata": {
"author": "New Author",
"category": "updated"
}
}'
HTTPie
http PUT [INSTANCE-URL]/mybucket.files/my-custom-id \
Authorization:"Basic [BASIC-AUTH]" \
Content-Type:application/json \
metadata:='{
"author": "New Author",
"category": "updated"
}'
JavaScript
fetch('[INSTANCE-URL]/mybucket.files/my-custom-id', {
method: 'PUT',
headers: {
'Authorization': 'Basic [BASIC-AUTH]',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"metadata": {
"author": "New Author",
"category": "updated"
}
})
})
.then(response => {
if (response.ok) {
console.log('File metadata replaced successfully');
} else {
console.error('Failed to replace file metadata:', response.status);
}
})
.catch(error => console.error('Error:', error));
Note
|
Update operators and aggregation pipelines cannot be used with file metadata updates. |
Deleting Files
To delete a file and all its chunks:
cURL
curl -i -X DELETE [INSTANCE-URL]/mybucket.files/my-custom-id \
-H "Authorization: Basic [BASIC-AUTH]"
HTTPie
http DELETE [INSTANCE-URL]/mybucket.files/my-custom-id \
Authorization:"Basic [BASIC-AUTH]"
JavaScript
fetch('[INSTANCE-URL]/mybucket.files/my-custom-id', {
method: 'DELETE',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => {
if (response.ok) {
console.log('File deleted successfully');
} else {
console.error('Failed to delete file:', response.status);
}
})
.catch(error => console.error('Error:', error));
Important Notes
-
RESTHeart automatically detects and sets the file’s content type
-
File operations don’t support write modes - POST is always insert, PUT is always upsert
-
File metadata can be queried with the same operators as regular documents
-
File buckets have two underlying collections in MongoDB:
<bucket-name>.files
for metadata and<bucket-name>.chunks
for content -
Binary content is accessed with the
/binary
suffix
Examples
Example 1: Upload and serve an image
cURL
# Upload an image
curl -i -X POST [INSTANCE-URL]/images.files \
-H "Authorization: Basic [BASIC-AUTH]" \
-F "file=@/path/to/logo.png" \
-F 'metadata={"purpose":"website"}'
HTTPie
# Upload an image
http --form POST [INSTANCE-URL]/images.files \
Authorization:"Basic [BASIC-AUTH]" \
file@/path/to/logo.png \
metadata='{"purpose":"website"}'
JavaScript
// Upload an image
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('metadata', JSON.stringify({"purpose":"website"}));
fetch('[INSTANCE-URL]/images.files', {
method: 'POST',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
},
body: formData
})
.then(response => {
if (response.ok) {
console.log('Image uploaded successfully');
return response.headers.get('Location');
} else {
console.error('Failed to upload image:', response.status);
}
})
.then(location => {
if (location) console.log('Image location:', location);
})
.catch(error => console.error('Error:', error));
Access the image in a web page:
<img src="[INSTANCE-URL]/images.files/60f8a7b9e4b053f542c13ece/binary" alt="Logo">
Example 2: Upload a document and track versions
cURL
# Upload initial version
curl -i -X PUT [INSTANCE-URL]/documents.files/contract-2023 \
-H "Authorization: Basic [BASIC-AUTH]" \
-F "file=@/path/to/document.pdf" \
-F 'metadata={"version":"1.0","author":"John"}'
HTTPie
# Upload initial version
http --form PUT [INSTANCE-URL]/documents.files/contract-2023 \
Authorization:"Basic [BASIC-AUTH]" \
file@/path/to/document.pdf \
metadata='{"version":"1.0","author":"John"}'
JavaScript
// Upload initial version
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('metadata', JSON.stringify({
"version": "1.0",
"author": "John"
}));
fetch('[INSTANCE-URL]/documents.files/contract-2023', {
method: 'PUT',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
},
body: formData
})
.then(response => {
if (response.ok) {
console.log('Document uploaded successfully');
} else {
console.error('Failed to upload document:', response.status);
}
})
.catch(error => console.error('Error:', error));
Update the file and increment version:
cURL
# Update the file and increment version
curl -i -X PUT [INSTANCE-URL]/documents.files/contract-2023 \
-H "Authorization: Basic [BASIC-AUTH]" \
-F "file=@/path/to/document_updated.pdf" \
-F 'metadata={"version":"1.1","author":"John","updated":"2023-07-15"}'
HTTPie
# Update the file and increment version
http --form PUT [INSTANCE-URL]/documents.files/contract-2023 \
Authorization:"Basic [BASIC-AUTH]" \
file@/path/to/document_updated.pdf \
metadata='{"version":"1.1","author":"John","updated":"2023-07-15"}'
JavaScript
// Update the file and increment version
const updatedFormData = new FormData();
updatedFormData.append('file', updatedFileInput.files[0]);
updatedFormData.append('metadata', JSON.stringify({
"version": "1.1",
"author": "John",
"updated": "2023-07-15"
}));
fetch('[INSTANCE-URL]/documents.files/contract-2023', {
method: 'PUT',
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
},
body: updatedFormData
})
.then(response => {
if (response.ok) {
console.log('Document updated successfully');
} else {
console.error('Failed to update document:', response.status);
}
})
.catch(error => console.error('Error:', error));