Don't reinvent file/object storage API

In this article we will compare HTTP API of solutions providing access to files via HTTP.

WebDAV

Old standard created in HTTP and XML times.

Pros:

Cons:

http://www.webdav.org/specs/rfc2518.html

S3

Originally created by Amazon for their S3 object storage. Later implemented by other object storage providers. IMHO very good alternative to WebDAV. All operations are compatible with HTTP methods. Uses XML responses, but not so complicated as WebDAV.

Pros:

Cons:

https://docs.aws.amazon.com/AmazonS3/latest/API/API_Operations_Amazon_Simple_Storage_Service.html

Seaweed Filer

Simple implementation of storage API POST method can upload file (from HTML form).

Pros:

Cons:

https://github.com/chrislusf/seaweedfs/wiki/Filer-Server-API

FileStash

Web browser for many backeds: S3, SFTP, WebDAV, MySQL, Dropbox, GDrive. Included in this comparison, because it has nice frontend and reinvented file access API.

https://www.filestash.app/

FileBrowser

Web browser for local file system, with material design UI. Included in this comparison, because it reinvented file access API.

https://filebrowser.org/

Pros:

Cons:

Comparison of APIs

We will be working with path /bucket/directory/file.txt and when there are no buckets we it is only directory.

List directory entries

WebDAV

GET /bucket/

S3

GET /bucket?prefix=/directory/&delimiter=/

Seaweed Filer

GET /bucket/directory/
Accept: application/json

FileStash

GET /api/files/ls?path=/directory/

FileBrowser

GET /api/resources/bucket/directory/

Create directory

WebDAV

MKCOL /bucket/directory/

S3, need to put some file in directory

PUT /bucket/directory/.keep

Filer:

FileStash

GET /api/files/mkdir?path=/bucket/directory/

FileBrowser

POST /api/resources/priecinok/?override=false

Create file

WebDAV

PUT /bucket/directory/file.txt

S3

PUT /bucket/directory/file.txt

Filer

PUT /bucket/directory/file.txt

FileStash

GET /api/files/touch?path=/bucket/directory/file.txt
or
POST /api/files/cat?path=/bucket/directory/file.txt
Content-Type: multipart/form-data

FileBrowser

POST /api/resources/bucket/directory/file.txt?override=false

Get file content

WebDAV

GET /bucket/directory/file.txt

S3

GET /bucket/directory/file.txt

Filer

GET /bucket/directory/file.txt

FileStash

GET /api/files/cat?path=/bucket/directory/file.txt

FileBrowser

GET /api/resources/bucket/directory/file.txt

Delete file

WebDAV

DELETE /bucket/directory/file.txt

S3

DELETE /bucket/directory/file.txt

Filer:

DELETE /bucket/directory/file.txt

FileStash

GET /api/files/rm?path=/bucket/directory/file.txt

FileBrowser

DELETE /api/resources/bucket/directory/file.txt

Copy file

WebDAV

COPY /bucket/directory/file.txt
Destination: /bucket/directory/new.txt

S3

PUT /bucket/directory/new.txt
X-Amz-Copy-Source /bucket/directory/file.txt

Filer:

GET /bucket/directory/file.txt

PUT /bucket/directory/new.txt

FileStash

GET /api/files/cp?from=/bucket/directory/file.txt&to=/bucket/directory/new.txt

FileBrowser

PATCH /api/resources/bucket/directory/file.txt?action=copy&destination=/bucket/directory/new.txt&override=false&rename=true

Move/Rename file

WebDAV

MOVE /bucket/directory/file.txt
Destination: /bucket/directory/new.txt

S3

PUT /bucket/directory/new.txt
DELETE /bucket/directory/file.txt

Filer:

FileStash

GET /api/files/mv?from=/bucket/directory/file.txt&from=/bucket/directory/new.txt

FileBrowser

PATCH /api/resources/bucket/directory/file.txt?action=rename&destination=/bucket/directory/new.txt&override=false&rename=false

Move/Rename directory

WebDAV

MOVE /bucket/directory/
Destination: /bucket/directory/

S3

recursively list, copy and delete each file

Filer:

FileStash

GET /api/files/mv?from=/bucket/directory/&from=/bucket/directory-new/

FileBrowser

PATCH /api/resources/bucket/directory/?action=copy&destination=/bucket/directory/&override=false&rename=true

Delete directory recursively

WebDAV

DELETE /bucket/directory/

S3

List files recursicely and DELETE each file

Filer

DELETE /bucket/directory/?recursive=true

FileStash

GET /api/files/rm?path=/bucket/directory/

FileBrowser

DELETE /api/resources/bucket/directory/

Check if file exists

WebDAV

HEAD /bucket/directory/file.txt

S3

HEAD /bucket/directory/file.txt

Filer

HEAD /bucket/directory/file.txt

FileStash

HEAD /api/files/cat?path=/bucket/directory/file.txt

FileBrowser

DELETE /api/resources/bucket/directory/file.txt

Create file if not exists

WebDAV

PUT /bucket/directory/file.txt
If-None-Match: *

S3

PUT /bucket/directory/file.txt
If-None-Match: *

Filer

HEAD /bucket/directory/file.txt
# if HEAD returned 404
PUT /bucket/directory/file.txt #(if HEAD returned 404)

FileStash

HEAD /api/files/cat?path=/bucket/directory/file.txt
# if HEAD returned 404
GET /api/files/cat?path=/bucket/directory/file.txt

FileBrowser

POST /api/resources/bucket/directory/file.txt?override=false

Upload large file (in chunks)

WebDAV (NextCloud)

MKCOL /.tmp-26e7beeca3c0/

PUT /.tmp-26e7beeca3c0/000000000000000-000000010485759
PUT /.tmp-26e7beeca3c0/000000010485760-000000015728640
...

MOVE /.tmp-26e7beeca3c0/.file
Destination: /bucket/directory/file.txt

S3

POST /bucket/directory/file.txt?uploads -> UPLOAD_ID

PUT /bucket/directory/file.txt?partNumber=1&uploadId=UPLOAD_ID
PUT /bucket/directory/file.txt?partNumber=2&uploadId=UPLOAD_ID
...

POST /bucket/directory/file.txt?uploadId=UPLOAD_ID

Filer

unknown

FileStash

unknown

FileBrowser

unknown

Append to file

Filer

PUT /bucket/directory/file.txt?op=append