Upload file to Synology Filestation over API (one more try)

Hi Node-REDers,

UweG already had the same question a few months ago. I decided to give this issue another push.

We are looking for help with a function node to call a http-request-node properly in order to upload a file to the Synology filesystem. We've figured out all the remaining API-Calls and the fundamental understanding of the post method is the problem, i guess.

msg.method = "POST";
msg.url = "?";
msg.headers = {?};
msg.payload = {?};
return msg;

The documentation on the SynologyAPI is a little bit weird when it comes to this topic. But maybe one of you guys could find sence in it. The following starts on page 69.
Synology_File_Station_API_Guide.pdf (629.9 KB)

SYNO.FileStation.Upload
Description Upload a file. Overview
Availability: Since DSM 6.0
Version: 2
Method upload
Description:
Upload a file by RFC 1867, RFC 1867 - Form-based File Upload in HTML. Note that each parameter is passed within each part but binary file data must be the last part.
Availability: Since version 2.

Request:
Parameter:

path | A destination folder path starting with a shared folder to which files can be uploaded. | String
create_parents | Create parent folder(s) if none exist. | Boolean
filename | (filepart) File content. Must be the last part. | Binary data

Example:
POST /webapi/entry.cgi
…
Content-Length:20326728
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="api"
SYNO.FileStation.Upload
--AaB03x
content-disposition: form-data; name="version"
2
--AaB03x
content-disposition: form-data; name="method"
upload
--AaB03x
content-disposition: form-data; name="path"
/upload/test
--AaB03x
content-disposition: form-data; name="create_parents"
true
--AaB03x
content-disposition: form-data; name="file"; filename="file1.txt"
Content-Type: application/octet-stream
... contents of file1.txt ...
--AaB03x--

Response:
No specific response. It returns an empty success response if completed without error.

Really hope someone could do a little bit of JavaScript wizardry and help us out :pray:

According to that document, you need to create a multipart form-data POST.

The built in docs of the HTTP Request node explain what headers and values you need to send.

Here is an (untested) example...

image

Flow (use CTRL-I to import)

[{"id":"2b377364e1c38834","type":"http request","z":"55525a9d18c99b86","name":"","method":"POST","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"headers":[],"x":650,"y":1060,"wires":[[]]},{"id":"2afa22ddfca54482","type":"inject","z":"55525a9d18c99b86","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":285,"y":1000,"wires":[["2ac84dacdaa772d5"]],"l":false},{"id":"5e7d5463bdc5ef3f","type":"file in","z":"55525a9d18c99b86","name":"Get file \"filename\"","filename":"filename","filenameType":"msg","format":"","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":770,"y":1000,"wires":[["5b885fa382a4078e"]]},{"id":"5b885fa382a4078e","type":"function","z":"55525a9d18c99b86","name":"Create multipart/form-data","func":"//set  my.syno.nas.ip  to IP or HOSTNAME of NAS\nmsg.url = \"http://my.syno.nas.ip/webapi/entry.cgi\";\n\nmsg.headers = {\n    \"content-type\": \"multipart/form-data\"\n}\n\nmsg.payload = {\n    \"api\": \"SYNO.FileStation.Upload\",\n    \"version\": \"2\",\n    \"method\": \"upload\",\n    \"path\": msg.uploadPath,//where to put file on nas\n    \"create_parents\": \"true\",\n    \"file\": {\n        \"value\": msg.payload, //file buffer\n        \"options\": {\n            \"filename\": msg.uploadFilename  //write to nas as this name\n        }\n    }\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":1060,"wires":[["2b377364e1c38834"]]},{"id":"2ac84dacdaa772d5","type":"change","z":"55525a9d18c99b86","name":"setup filename, uploadPath, uploadFilename","rules":[{"t":"set","p":"filename","pt":"msg","to":"c:/temp/test.txt","tot":"str"},{"t":"set","p":"uploadPath","pt":"msg","to":"/data/temp","tot":"str"},{"t":"set","p":"uploadFilename","pt":"msg","to":"test.txt","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":1000,"wires":[["5e7d5463bdc5ef3f"]]}]

You will need to open the "setup filename" and "create multipart" nodes & set the variables accordingly.

Good luck

1 Like

Yes Steve you made my week!!! This is totally working! :man_cartwheeling:

After logging in to the API we need to provide the SID as well as the port in the URL, but this is all I changed from your example!

For the basic understanding, the read-file-node provides a buffer in msg.payload and the function-node calls the http-request-node. It is constructed like the following code
temp

//after API-Login store SID with flow.set('SYNO-SID-01', msg.payload.data.sid)
msg.method = "POST";
msg.url = "https://NAS-IP:PORT/webapi/entry.cgi?_sid="+flow.get('SYNO-SID-01');
msg.headers = {'Content-Type': "multipart/form-data"};
msg.payload = {
            'api' : "SYNO.FileStation.Upload",
            'version' : "2",
            'method' : "upload",
            'path' : "/YOUR-SHARE/YOUR-FOLDER", //path to parent folder
            'create_parents' : "true", //create parents if necessary
            'file': {
                        'value': msg.payload, //file buffer of read-file-node
                        'options': {
                                    'filename': "FILENAME.txt" //filename
                        }
            }
};

return msg;

Hope this helps someone else and a lot of gratitude for the solution, Steve-Mcl you are a legend :heart:

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.