3.3 Files

3.3.1 Download file

Each file resource has a related link named "content" (href: "/files/{id}") that can be used to download the file content.  For example, take the following folder listing:

[Request]
> curl -k -u dlewis:novell https://amethyst.provo.novell.com:8443/rest/self/my_files/library_files

[Response]
{
  "first": 0,
  "count": 15,
  "total": 15,
  "items": [{
    "id": "09c1c3fb5256e2e4015256e8691c003b",
    "doc_type": "file",
    "href": "/files/09c1c3fb5256e2e4015256e8691c003b/metadata",
    "name": "test.txt",
    "length": 14,
    "links":[{
      "rel": "content",
      "href": "/files/09c1c3fb5256e2e4015256e8691c003b"
    },...],
    ...
  },...
}

The following illustrates how to download the file:

[Request]
> curl -k -u dlewis:novell \
  https://amethyst.provo.novell.com:8443/rest/files/09c1c3fb5256e2e4015256e8691c003b -o test.txt

[Response]
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    14  100    14    0     0     28      0 --:--:-- --:--:-- --:--:--    28

3.3.2 Upload new file

To upload a new file, use the "child_library_folders" link of the parent folder where the file should reside.  For example, take the following folder listing:

[Request]
> curl -k -u dlewis:novell https://amethyst.provo.novell.com:8443/rest/self/my_files/library_children

[Response]
{
  "first": 0,
  "count": 24,
  "total": 24,
  "items": [{
    "id": 48,
    "doc_type": "binder",
    "entity_type": "folder",
    "href": "/folders/48",
    "title": "A",
    "links":[{
      "rel": "child_library_files",
      "href": "/folders/48/library_files"
    },...],
    ...
  },...
}

The "child_library_files" location for this folder is "/folders/48/library_files".  To upload a file send a POST request to that resource.  You must use the file_name query parameter to specify the name of the file.  If successful, the response is the FileProperties representation of the newly added file.

[Request]
>  curl -k -u dlewis:novell https://amethyst.provo.novell.com:8443/rest/folders/48/library_files?file_name=aaa.txt \
   -X POST -H "Content-Type: application/octet-stream" --upload-file ./test.txt

[Response]
{
  "id":"09c1c3fb530f562401531018f4270000",
  "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"},
  "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"},
  "length":14,
  "md5":"07b4778d21a1673c60bb650a7c1a4055",
  "name":"aaa.txt",
  "href":"/files/09c1c3fb530f562401531018f4270000/metadata",
  "links":[...],
  "doc_type": "file",
  "version_number": 1,
  "owning_entity": {"id":61,"type":"folderEntry","href":"/folder_entries/61"},
  "parent_binder": {"id":48,"href":"/binders/48"}
}

The REST interface also supports "Content-Type: multipart/form-data".

If a file already exists with that name, the server will return an HTTP 409 Conflict status code.  The response body will be an ErrorInfo object with a "FILE_EXISTS" code and the existing FileProperties resource:

[Request]
>  curl -k -u dlewis:novell https://amethyst.provo.novell.com:8443/rest/folders/48/library_files?file_name=aaa.txt \
   -X POST -H "Content-Type: application/octet-stream" --upload-file ./test.txt

[Response]
{
  "code":"FILE_EXISTS",
  "message":"A file with the name already exists.",
  "data":{
    "id":"09c1c3fb530f562401531018f4270000",
    "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"},
    "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"},
    "length":14,
    "md5":"07b4778d21a1673c60bb650a7c1a4055",
    "name":"aaa.txt",
    "href":"/files/09c1c3fb530f562401531018f4270000/metadata",
    "links":[...],
    "doc_type": "file",
    "version_number":1,
    "owning_entity":{"id":61,"type":"folderEntry","href":"/folder_entries/61"},
    "parent_binder":{"id":48,"href":"/binders/48"}
  }
}

3.3.3 Replace existing file

There are two ways to overwrite an existing file.  The first option is upload it as a new file to the parent folder's "child_library_files" link and add the "overwrite_existing=true" query parameter:

[Request]
>  curl -k -u dlewis:novell \
   "https://amethyst.provo.novell.com:8443/rest/folders/48/library_files?file_name=aaa.txt&overwrite_existing=true" \
   -X POST -H "Content-Type: application/octet-stream" --upload-file ./test.txt

[Response]
{
  "id":"09c1c3fb530f562401531018f4270000",
  "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"},
  "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:59:24Z"},
  "length":24,
  "md5":"7eda124afb39fddc0b2e11ce45662e75",
  "name":"aaa.txt",
  "href":"/files/09c1c3fb530f562401531018f4270000/metadata",
  "links":[...],
  "doc_type": "file",
  "version_number": 2,
  "owning_entity": {"id":61,"type":"folderEntry","href":"/folder_entries/61"},
  "parent_binder": {"id":48,"href":"/binders/48"}
}

If no file exists in the folder with the given name, the file will add to the folder as a new file.

The other option is to send a POST request to the "content" related link of the existing FileProperties object (href: "/files/{id}").  You must specify one of two query parameters: "force_overwrite=true" or "last_version={version_number}".  The "force_overwrite=true" option will overwrite the current version of the file without doing any version conflict checks:

[Request]
>  curl -k -u dlewis:novell \
   "https://amethyst.provo.novell.com:8443/rest/files/09c1c3fb530f562401531018f4270000?force_overwrite=true" \
   -X POST -H "Content-Type: application/octet-stream" --upload-file ./test.txt

[Response]
{
  "id":"09c1c3fb530f562401531018f4270000",
  "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"},
  "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T22:07:13Z"},
  "length":45,
  "md5":"919fd4f5a0cd091d34aeb09583068834",
  "name":"aaa.txt",
  "href":"/files/09c1c3fb530f562401531018f4270000/metadata",
  "links":[...],
  "doc_type": "file",
  "version_number": 3,
  "owning_entity": {"id":61,"type":"folderEntry","href":"/folder_entries/61"},
  "parent_binder": {"id":48,"href":"/binders/48"}
}

However, if the client application can track file version numbers, specifying "last_version={version_number}" is the better option because it prevents users from overwriting each others' modifications to the file.  If user A downloads and edits version 3 of the file in the client application, the client application can upload the new version of the file as follows:

[Request]
>  curl -k -u dlewis:novell \
   "https://amethyst.provo.novell.com:8443/rest/files/09c1c3fb530f562401531018f4270000?last_version=3" \
   -X POST -H "Content-Type: application/octet-stream" --upload-file ./test.txt

[Response]
{
  "id":"09c1c3fb530f562401531018f4270000",
  "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"},
  "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T22:17:24Z"},
  "length":43,
  "md5":"99a3b991e1b7e7ddfd6be1251402fd1f",
  "name":"aaa.txt",
  "href":"/files/09c1c3fb530f562401531018f4270000/metadata",
  "links":[...],
  "doc_type": "file",
  "version_number": 4,
  "owning_entity": {"id":61,"type":"folderEntry","href":"/folder_entries/61"},
  "parent_binder": {"id":48,"href":"/binders/48"}
}

This request succeeds because the file version at the time of the upload matches the version in "last_version".  If user B also downloads and edits version 3 of the file, the upload will fail with and HTTP 409 (Conflict) status code because user A already modified it and the version number doesn't match the "last_version" query parameter.  The response body is an ErrorInfo object with a "FILE_VERSION_CONFLICT" code and the latest file metadata:

[Request]
>  curl -k -u dlewis:novell \
   "https://amethyst.provo.novell.com:8443/rest/files/09c1c3fb530f562401531018f4270000?last_version=3" \
   -X POST -H "Content-Type: application/octet-stream" --upload-file ./test.txt

[Response]
{
 "code":"FILE_VERSION_CONFLICT",
 "message":"A file with the name already exists.",
 "data":{
   "id":"09c1c3fb530f562401531018f4270000",
   "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"},
   "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T22:17:24Z"},
   "length":43,
   "md5":"99a3b991e1b7e7ddfd6be1251402fd1f",
   "name":"aaa.txt",
   "href":"/files/09c1c3fb530f562401531018f4270000/metadata",
   "links":[...],
   "doc_type": "file",
   "version_number":4,
   "owning_entity":{"id":61,"type":"folderEntry","href":"/folder_entries/61"},
   "parent_binder":{"id":48,"href":"/binders/48"}
 }
}

3.3.4 Rename file

To rename a file, use the "name" related link of the FileProperties object (href: "/files/{id}/name").  The Content-Type must be "application/x-www-form-urlencoded" and the new name of the file is specified by the "name" form parameter.  The REST interface returns the full FileProperties resource in the response.

[Request]
> curl -k -u dlewis:novell "https://amethyst.provo.novell.com:8443/rest/files/09c1c3fb530f562401531018f4270000/name" 
  -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "name=aaa%20renamed.txt"

[Response]
{
  "id":"09c1c3fb530f562401531018f4270000", 
  "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"}, 
  "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T22:17:24Z"}, 
  "length":43, 
  "md5":"99a3b991e1b7e7ddfd6be1251402fd1f", 
  "name":"aaa renamed.txt", 
  "href":"/files/09c1c3fb530f562401531018f4270000/metadata", 
  "links":[...], 
  "doc_type": "file", 
  "version_number":4, 
  "owning_entity":{"id":61,"type":"folderEntry","href":"/folder_entries/61"}, 
  "parent_binder":{"id":48,"href":"/binders/48"}
}

The name in the POST form data should be a UTF-8 string that has been URL encoded.

3.3.5 Move file

To move a file, use the "parent_folder" related link of the FileProperties object (href: "/files/{id}/parent_folder").  The Content-Type must be "application/x-www-form-urlencoded" and the parent folder to which the file should be moved is specified by the "folder_id" form parameter.  The REST interface returns the full FileProperties resource in the response.

[Request]
> curl -k -u dlewis:novell \
  "https://amethyst.provo.novell.com:8443/rest/files/09c1c3fb530f562401531018f4270000/parent_folder" \
  -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "folder_id=49"

[Response]
{
  "id":"09c1c3fb530f56240153105273a40009", 
  "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T21:46:23Z"}, 
  "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T22:17:24Z"}, 
  "length":43, 
  "md5":"99a3b991e1b7e7ddfd6be1251402fd1f", 
  "name":"aaa renamed.txt", 
  "href":"/files/09c1c3fb530f56240153105273a40009/metadata", 
  "links":[...], 
  "doc_type": "file", 
  "version_number":4, 
  "owning_entity":{"id":62,"type":"folderEntry","href":"/folder_entries/62"}, 
  "parent_binder":{"id":49,"href":"/binders/49"}
}

It's important to note that the file ID and the owning_entity ID have changed in the above response.  In certain cases, for example when moving a file from personal storage to a net folder or moving a file between net folders, the move operation is implemented as a copy operation and a delete operation.  For this reason, the file and it's associated folder entry are assigned new IDs.

Optionally, you can specify a new name for the file as well with the "name" form parameter:

[Request]
> curl -k -u dlewis:novell \
  "https://amethyst.provo.novell.com:8443/rest/files/09c1c3fb530f562401531018f4270000/parent_folder" \
  -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "folder_id=48&name=aaa.txt"

[Response]
...

The name in the POST form data should be a UTF-8 string that has been URL encoded.

3.3.6 Copy file

The "child_library_files" related link of a Folder can be used to copy a file into that folder.  The Content-Type must be "application/x-www-form-urlencoded" and the source file which is to be copied into the folder is specified by the "source_id" form parameter.  The name of the new file is specified by the "file_name" form parameter.  The REST interface returns the FileProperties representation of the new file in the response.

For example, the "child_library_files" related link of the My Files top level folder is "/self/my_files/library_files".  The following copes a file into that folder:

[Request]
> curl -k -u dlewis:novell "https://amethyst.provo.novell.com:8443/rest/self/my_files/library_files" \
  -X POST -H "Content-Type: application/x-www-form-urlencoded" \
  -d "source_id=09c1c3fb530f56240153105273a40009&file_name=aaa%20copied.txt"

[Response]
{
  "id":"09c1c3fb530f562401531070137b000e",
  "creation":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T23:21:33Z"},
  "modification":{"principal":{"id":20,"href":"/users/20"},"date":"2016-02-23T22:18:18Z"},
  "length":43,
  "md5":"99a3b991e1b7e7ddfd6be1251402fd1f",
  "name":"aaa copied.txt",
  "href":"/files/09c1c3fb530f562401531070137b000e/metadata",
  "links":[...],
  "doc_type": "file",
  "version_number":1,
  "owning_entity":{"id":63,"type":"folderEntry","href":"/folder_entries/63"},
  "parent_binder":{"id":-100,"href":"/self/my_files"}
}

3.3.7 Delete file

To delete a file, send DELETE request to the "content" related link of the FilrProperites resource:

[Request]
> curl -v -k -u dlewis:novell \
  https://amethyst.provo.novell.com:8443/rest/files/09c1c3fb530f562401531070137b000e -X DELETE

[Response]
< HTTP/1.1 204 No Content

If successful, the REST interface returns an HTTP 204 (No Content) status code with no response body.