Combine FilePond with Pintura and create the perfect image edit and upload experience.
The server
property can be configured to link to the server API endpoints. Only after these have been configured can FilePond asynchronously upload files to a server.
We'll first go over the different end points and what they do before discussing how to configure them. The advanced section covers how to use functions to fully change how FilePond interacts with the server.
Asynchronously uploading files with FilePond is called processing. In short, FilePond sends a file to the server and expects the server to return a unique file id. This unique id is then used to revert uploads or restore earlier uploads.
Along with the file object, FilePond also sends the file metadata to the server, both these objects are given the same name
.
The upload process described over time:
my-file.jpg
as multipart/form-data
using a POST
requesttmp/12345/my-file.jpg
12345
in text/plain
response12345
in a hidden input fieldtmp/12345/my-file.jpg
to its final location and remove the tmp/12345
folderFilePond uses unique file ids to prevent showing information about the server file structure to the client.
To process files in chunks set chunkUploads
to true
.
FilePond will then slice up files bigger than the set chunkSize
into parts. Files smaller than the chunkSize
will be posted to the process
end point. If you want to force all files to be posted to the chunk end point set chunkForce
to true
.
Custom headers used in requests
Header | Description |
---|---|
Upload-Length
| The total size of the file being transferred |
Upload-Name
| The name of the file being transferred |
Upload-Offset
| The offset of the chunk being transferred |
Content-Type
| The content type of a patch request, set to 'application/offset+octet-stream'
|
In short:
POST
request (without file) to start a chunked transfer, expecting to receive a unique transfer id in the response body, it'll add the Upload-Length
header to this request.PATCH
request to push a chunk to the server. Each of these requests is accompanied by a Content-Type
, Upload-Offset
, Upload-Name
, and Upload-Length
header.HEAD
request to determine which chunks have already been uploaded, expecting the file offset of the next expected chunk in the Upload-Offset
response header.In detail:
POST
request. The request is accompanied by the metadata and the total file upload size set to the Upload-Length
header.tmp/12345/
12345
in text/plain
response12345
in file itemPATCH
request adding the unique id 12345
in the URL, each PATCH
request is accompanied by a Upload-Offset
, Upload-Length
, and Upload-Name
header. The Upload-Offset
header contains the byte offset of the chunk, the Upload-Length
header contains the total file size, the Upload-Name
header contains the file name.12345
as the server id of this file.tmp/12345/my-file.jpg
to its final location and remove the tmp/12345
folderIf one of the chunks fails to upload after the set amount of retries in chunkRetryDelays
the user has the option to retry the upload.
HEAD
request accompanied by the transfer id (12345
) in the URL.Upload-Offset
set to the next expected chunk offset in bytes.Everything continues like normal.
There's one way the client can deviate from the previous path and that is by reverting the upload. Let's go back to step five and switch to this alternate reality.
DELETE
request with 12345
as body by tapping the undo button
tmp/12345
and returns an empty response
This is another reason why FilePond uses unique ids. If we're going to give the client the power to influence the server file system that power should be very minimal.
FilePond uses the restore
end point to restore temporary server files. This might be useful in a situation where the user closes the browser window but hadn't finished completing the form. Temporary files can be set with the files
property.
Step one and two now look like this.
12345
using a GET
requestContent-Disposition: inline; filename="my-file.jpg"
If this is a CORS request we need to explicitely allow access to the Content-Disposition
header in the preflight CORS response by settings the Access-Control-Expose-Headers
header like this Access-Control-Expose-Headers: Content-Disposition
The restore
end point is used to restore a temporary file, the load
end point is used to restore already uploaded server files. These files might be located in a database or somewhere on the server file system. Either way they might not be directly accessible from the web.
For situations where a user might want to edit an existing file selection we can use the load
end point to restore those files.
12345
or a file name using a GET
requestContent-Disposition: inline; filename="my-file.jpg"
If this is a CORS request we need to explicitely allow access to the Content-Disposition
header in the preflight CORS response by settings the Access-Control-Expose-Headers
header like this Access-Control-Expose-Headers: Content-Disposition
The fetch
end point is used to load files located on remote servers. When a user drops a remote link, FilePond asks the server to download it (CORS might otherwise block it). In this situation the server serves as a proxy.
http://somewhere/their-file.jpg
using a GET
requestAn alternative is to configure FilePond to only do a HEAD
request. The server should then save the file to tmp/12345/my-file.jpg
and return response headers with the required file information.
header('Access-Control-Expose-Headers: Content-Disposition, Content-Length, X-Content-Transfer-Id');
header('Content-Type: image/jpeg');
header('Content-Length: 3965123');
header('Content-Disposition: inline; filename="my-file.jpg"');
header('X-Content-Transfer-Id: 12345');
The remove
end point is used to remove local
files located on the server. This end point is not enabled by default and can only be set to a custom function.
The server
configuration property expects an object or a URL. If it's not defined, FilePond will not be able to upload file to the server or use fetch functionality.
Setting a single URL is the most basic form of defining a server configuration.
FilePond.setOptions({
server: './',
});
This tells FilePond the api is located at the same location as the current page. It will then assume it can call all methods on this url. Like shown below.
Method | Type | Path |
---|---|---|
process
| POST
| |
revert
| DELETE
| |
load
| GET
| ?load=<source>
|
restore
| GET
| ?restore=<id>
|
fetch
| GET | HEAD
| ?fetch=<url>
|
patch
| PATCH
| ?patch=<id>
|
We can of course supply a path or URL to another location, FilePond will simply append the above default paths to the supplied value. If we want more fine grained control we can use an object to configure the server end points.
To setup asynchronous uploading only, we pass the location of the process end point.
FilePond.setOptions({
server: {
process: './process',
fetch: null,
revert: null,
},
});
This configuration assumes that the process
end point is located on the same server. Reverting a file upload and fetching a remote file have been disabled. Restoring or loading an earlier uploaded file with this configuration is also not possible.
To unlock these features we have to supply FilePond with some more end points using the revert
, fetch
, load
and restore
properties.
FilePond.setOptions({
server: {
process: './process',
revert: './revert',
restore: './restore/',
load: './load/',
fetch: './fetch/',
},
});
FilePond will append the dropped URL to the fetch
method, and the unique file id will automatically be added to the restore
and load
end points. restore
, load
and fetch
are GET
requests while process
is a POST
request and revert
is a DELETE
request.
If the endpoints are located on a different server we can add a url
property to tell FilePond its location.
FilePond.setOptions({
server:{
url: 'http://192.168.0.100',
process: './process',
revert: './revert',
restore: './restore/',
load: './load/',
fetch: './fetch/'
});
Depending on our project we might have to pass additional information to each request. We can accomplish this by turning the end point into an object which allows for more fine grain control over how FilePond handles each request.
For brevity we'll only look at the process
property. All other properties can be configured with the same configuration object.
FilePond.setOptions({
server: {
url: 'http://192.168.0.100',
process: {
url: './process',
method: 'POST',
withCredentials: false,
headers: {},
timeout: 7000,
onload: null,
onerror: null,
ondata: null,
},
},
});
Property | Description | Required |
---|---|---|
url
| Path to the end point | yes |
method
| Request method to use | no |
withCredentials
| Toggles the XMLHttpRequest withCredentials on or off | no |
headers
| An object containing additional headers to send, or when uploading chunks this can be a function that is expected to return a header object | no |
timeout
| Timeout for this action | no |
onload
| Called when server response is received, useful for getting the unique file id from the server response | no |
onerror
| Called when server error is received, receives the response body, useful to select the relevant error data | no |
ondata
| Called with the formdata object right before it is sent, return extended formdata object to make changes | no |
A more elaborate server configuration is shown below. This configuration reveals the timeout
property as assigned to the server object. This sets it for all end points, it can also be configured per end point.
FilePond.setOptions({
server: {
url: 'http://192.168.0.100',
timeout: 7000,
process: {
url: './process',
method: 'POST',
headers: {
'x-customheader': 'Hello World',
},
withCredentials: false,
onload: (response) => response.key,
onerror: (response) => response.data,
ondata: (formData) => {
formData.append('Hello', 'World');
return formData;
},
},
revert: './revert',
restore: './restore/',
load: './load/',
fetch: './fetch/',
},
});
If we want to disable certain end points we can pass a null
instead of string or object. Say we only want to use the fetch functionality and not do asynchronous uploading we can disable processing. In that situation revert and restore do not make a lot of sense (since we're no longer uploading temporary files) so we can remove those.
FilePond.setOptions({
server: {
url: 'http://192.168.0.100',
timeout: 7000,
process: null,
load: './load/',
fetch: './fetch/',
},
});
If we require even more control we can configure each end point as a function instead of an object. FilePond will then run our function and supply callback methods to control the FilePond interface.
Note that in the examples below we make use of arrow functions, these can of course also be written as a classic function.
The custom process
function receives a file
object plus a set of FilePond callback methods to return control to FilePond. The file
parameter contains the native file object (instead of a FilePond file item) access the file item is restricted in the process
function to prevent setting properties or running functions that would would contradict or interfere with the current processing of the file.
The transfer
and options
parameters are only to be used when uploading chunks. Use transfer
to return the transfer id to FilePond, the options
parameter contains the chunk related options.
FilePond.setOptions({
server: {
process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
// fieldName is the name of the input field
// file is the actual file object to send
const formData = new FormData();
formData.append(fieldName, file, file.name);
const request = new XMLHttpRequest();
request.open('POST', 'url-to-api');
// Should call the progress method to update the progress to 100% before calling load
// Setting computable to false switches the loading indicator to infinite mode
request.upload.onprogress = (e) => {
progress(e.lengthComputable, e.loaded, e.total);
};
// Should call the load method when done and pass the returned server file id
// this server file id is then used later on when reverting or restoring a file
// so your server knows which file to return without exposing that info to the client
request.onload = function () {
if (request.status >= 200 && request.status < 300) {
// the load method accepts either a string (id) or an object
load(request.responseText);
} else {
// Can call the error method if something is wrong, should exit after
error('oh no');
}
};
request.send(formData);
// Should expose an abort method so the request can be cancelled
return {
abort: () => {
// This function is entered if the user has tapped the cancel button
request.abort();
// Let FilePond know the request has been cancelled
abort();
},
};
},
},
});
Custom revert methods receive the unique server file id and a load and error callback.
FilePond.setOptions({
server: {
revert: (uniqueFileId, load, error) => {
// Should remove the earlier created temp file here
// ...
// Can call the error method if something is wrong, should exit after
error('oh my goodness');
// Should call the load method when done, no parameters required
load();
},
},
});
Custom load methods receive the local file source
, and the callback methods: load
, error
, abort
, and headers
.
FilePond.setOptions({
server: {
load: (source, load, error, progress, abort, headers) => {
// Should request a file object from the server here
// ...
// Can call the error method if something is wrong, should exit after
error('oh my goodness');
// Can call the header method to supply FilePond with early response header string
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders
headers(headersString);
// Should call the progress method to update the progress to 100% before calling load
// (endlessMode, loadedSize, totalSize)
progress(true, 0, 1024);
// Should call the load method with a file object or blob when done
load(file);
// Should expose an abort method so the request can be cancelled
return {
abort: () => {
// User tapped cancel, abort our ongoing actions here
// Let FilePond know the request has been cancelled
abort();
},
};
},
},
});
The custom fetch method receives the url
to fetch and a set of FilePond callback methods to return control to FilePond.
FilePond.setOptions({
server: {
fetch: (url, load, error, progress, abort, headers) => {
// Should get a file object from the URL here
// ...
// Can call the error method if something is wrong, should exit after
error('oh my goodness');
// Can call the header method to supply FilePond with early response header string
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders
headers(headersString);
// Should call the progress method to update the progress to 100% before calling load
// (computable, loadedSize, totalSize)
progress(true, 0, 1024);
// Should call the load method with a file object when done
load(file);
// Should expose an abort method so the request can be cancelled
return {
abort: () => {
// User tapped abort, cancel our ongoing actions here
// Let FilePond know the request has been cancelled
abort();
},
};
},
},
});
Custom restore methods receive the server file id of the file to restore and a set of FilePond callback methods to return control to FilePond.
FilePond.setOptions({
server: {
restore: (uniqueFileId, load, error, progress, abort, headers) => {
// Should get the temporary file object from the server
// ...
// Can call the error method if something is wrong, should exit after
error('oh my goodness');
// Can call the header method to supply FilePond with early response header string
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders
headers(headersString);
// Should call the progress method to update the progress to 100% before calling load
// (computable, loadedSize, totalSize)
progress(true, 0, 1024);
// Should call the load method with a file object when done
load(serverFileObject);
// Should expose an abort method so the request can be cancelled
return {
abort: () => {
// User tapped abort, cancel our ongoing actions here
// Let FilePond know the request has been cancelled
abort();
}
};
};
}
});
The custom remove method receives the local file source
and a load
and error
callback.
This method is null
by default as giving clients the power to remove files from the server in this way might not be very secure. But, because of popular demand the method has been added.
FilePond.setOptions({
server: {
remove: (source, load, error) => {
// Should somehow send `source` to server so server can remove the file with this source
// Can call the error method if something is wrong, should exit after
error('oh my goodness');
// Should call the load method when done, no parameters required
load();
},
},
});