Community Tip - Have a PTC product question you need answered fast? Chances are someone has asked it before. Learn about the community search. X
Today we're going to learn how to use the Axeda Platform SDK v2 APIs to upload a file to the platform and create a software package. This document is a work in progress, but we're going to show you everything you need to get started. In my case I am using the very useful and easy to use Postman REST Client app available from the Chrome Store. I'll be using some terms below (API Object Names) that can be found in the documents listed in the bibliography at the end of this article.
Assumptions (Replace these with your own versions):
First things first, we need to authenticate to the platform and get a session id (header x_axeda_wss_sessionid).
(Note: Postman does not automatically URL encode query parameters - this can be especially important for the password)
You'll receive a response like this following:
<ns1:WSSessionInfo xmlns:ns1="http://type.v1.webservices.sl.axeda.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:WSSessionInfo">
<ns1:created>2015-06-02T15:16:49 +0000</ns1:created>
<ns1:expired>false</ns1:expired>
<ns1:sessionId>1a5XXXXX-d9aa-47f2-ac4f-28765ce5dbc5</ns1:sessionId>
<ns1:sessionTimeout>1800</ns1:sessionTimeout>
</ns1:WSSessionInfo>
Excellent, now we have a session id!
For the rest of the API calls (unless otherwise indicated), all of the following headers are set to the following:
The next step is to get our ModelReference:
POST: https://axedaplatform.example.com/services/v2/rest/model/findOne
<?xml version="1.0" encoding="UTF-8"?>
<ModelCriteria xmlns="http://www.axeda.com/services/v2">
<modelNumber>MyModelName</modelNumber>
</ModelCriteria>
Which will return output like:
<v2:Model xmlns:v2="http://www.axeda.com/services/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
id="MyModelName" systemId="6141" label="managed" detail="MyModelName"
restUrl="https://sandbox.axeda.com/services/v2/rest/model/id/6141">
<v2:name>MyModelName</v2:name>
<v2:modelNumber>MyModelName</v2:modelNumber>
<v2:autoRegisterAssets>false</v2:autoRegisterAssets>
<v2:type>MANAGED</v2:type>
...
</v2:Model>
The key piece of information we need from that request is the systemId.
A little bit about our file (lorem-ipsum.txt):
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla.
The next step is to create a FileUploadSession and upload our file. This will create for us the FileInfoReference we need to create our SoftwarePackage.
PUT: https://axedaplatform.example.com/services/v2/rest/file/session
BODY:
<?xml version="1.0"?>
<FileUploadSession xmlns='http://www.axeda.com/services/v2'>
<files>
<file xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:type='FileInfo'>
<filename>lorem-ipsum.txt</filename>
<md5>22b229c7ecc49cfa11255beb06c7f4fe</md5>
<filesize>307</filesize>
<contentType>application/text</contentType>
</file>
</files>
<expirationDate/>
<status/>
<updatedDate/>
<username/>
<version/>
</FileUploadSession>
And our response if all goes OK (HTTP 200) looks like the following:
<v2:ExecutionResult xmlns:v2="http://www.axeda.com/services/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" successful="true" totalCount="1">
<v2:succeeded>
<v2:success xsi:type="v2:FileUploadSessionSuccessfulOperation">
<v2:ref>16265</v2:ref>
<v2:id>16265</v2:id>
<v2:uploadUri>sftp://DISABLED</v2:uploadUri>
<v2:session systemId="16265" label="16265" detail="16265"
restUrl="https://sandbox.axeda.com/services/v2/rest/file/id/16265">
<v2:files>
<v2:file xsi:type="v2:FileInfo" id="1068731" systemId="1068731"
label="lorem-ipsum.txt" detail="1068731">
...
</v2:success>
</v2:succeeded>
</v2:ExecutionResult>
In this case, we just need the value of <v2:file systemId>, which is 1068731.
TIME TO UPLOAD THE FILE CONTENTS!!!
PUT: https://axedaplatform.example.com/services/v2/rest/file/1068731/content/
Extra Headers:
BODY: There needs to be a mime-part called 'file-content' that contains the contents or lorem-ipsum.txt
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file-content"; filename="cfk-lorem-ipsum.txt"
Content-Type: text/plain
----WebKitFormBoundary7MA4YWxkTrZu0gW
Note: If using Postman, SoapUI or other automated tool, this will be handled automatically for you - do not specify a Content-Type header in this case.
And our response, assuming an HTTP 200:
<v2:ExecutionResult xmlns:v2="http://www.axeda.com/services/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" successful="true" totalCount="1">
<v2:succeeded>
<v2:success>
<v2:ref>1068731</v2:ref>
<v2:id>1068731</v2:id>
</v2:success>
</v2:succeeded>
<v2:failures />
</v2:ExecutionResult>
This is just confirming our success! Excellent. Now we come to the SoftwarePackage. We need two key pieces of information, the ModelReference (6141) and the FileInfoReference (1068731):
POST: https://axedaplatform.example.com/services/v2/rest/softwarePackage
Headers: Our defaults, Content-Type and x_axeda_wss_sessionid
BODY:
<?xml version="1.0" encoding="UTF-8"?>
<SoftwarePackage xmlns="http://www.axeda.com/services/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>TEST-REST-PACKAGE</name>
<model systemId="6141" />
<version>1.0.0.1</version>
<primaryAgentsOnly>true</primaryAgentsOnly>
<retriesEnabled>true</retriesEnabled>
<instructions>
<instruction xsi:type="DownloadFileInstruction">
<file xsi:type="FileInfo" systemId="1068731"/>
<destinationDirectory>C:\temp</destinationDirectory>
<compressed>false</compressed>
<executable>false</executable>
<pathRelative>false</pathRelative>
<overwriteExistingEnabled>true</overwriteExistingEnabled>
</instruction>
</instructions>
</SoftwarePackage>
And our results:
<v2:ExecutionResult xmlns:v2="http://www.axeda.com/services/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" successful="true" totalCount="1">
<v2:succeeded>
<v2:success>
<v2:ref>TEST-REST-PACKAGE||1.0.0.1</v2:ref>
<v2:id>45863</v2:id>
</v2:success>
</v2:succeeded>
<v2:failures />
</v2:ExecutionResult>
And PROOF!
I hope this helps you in your projects, and helps demystify the Axeda Platform REST API a little for you.
Regards,
-Chris
Bibliography (Documents available from Support Portal):
Change History:
2015-09-24 : Change HTTP Methods of session create and content send to PUT from POST
Hi ,
I am trying to follow the instructions on this post and upload a file but it's not working for me . here is what i have done
1. i am able to successfully authenticate and get the session id.
2. I can also successfully create a FileUploadSession . The file i need to upload only contains the character "a" . So the MD5 i am using is "0cc175b9c0f1b6a831c399e269772661" and the filesize is "1".
3. Now when i try to upload the contents , i get the following response
<v2:failures><v2:failure code="ILLEGAL_ARGUMENT"><v2:ref>4153</v2:ref><v2:message>The argument is invalid. MD5 comparison failed</v2:message><v2:sourceOfFailure>fileInfo.md5</v2:sourceOfFailure></v2:failure></v2:failures>
Here is my request body for file upload session
<?xml version="1.0"?><FileUploadSession xmlns="http://www.axeda.com/services/v2"><files><file xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="FileInfo"><filename>lorem-ipsum.txt</filename><md5>0cc175b9c0f1b6a831c399e269772661</md5><filesize>1</filesize><contentType>application/text</contentType></file></files><expirationDate/><status/><updatedDate/><username/><version/></FileUploadSession>
and request body for content upload
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file-content"; filename="lorem-ipsum.txt"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
a
----WebKitFormBoundary7MA4YWxkTrZu0gW
Any ideas??
My guess is we're counting the newline, so the content is really a\r\n (assuming Windows). What tool are you using to do your upload?
Even if i change the md5 to that of "a/r/n" which is 933222B19FF3E7EA5F65517EA1F7D57E( even tried 94364860a0452ac23f3dac45f0091d81 by doing md5sum on a unix box) and keep my file unchanged (i.e. the file only contains "a" ) , i get the same response.I am calling the api from c# .
One more thing , if i get rid of the md5 from the file session request body and just pass the file size and file name , the upload response is a success but the file status becomes invalid
How are you creating the file? What tool?
Hi,
I am following your instructions,
1. I have created FileUploadSession successfully
2. Now try to upload file content, it block me - HTTP 200 returned but no message returned..
So I don't know what happened and is there something wrong.
Below is my request body,
On the body tab, instead of raw, pick "form-data".
Then choose the example file, and give it the key "file-content" and set the type to "File".
Regards,
-Chris Kaminski
PTC/Axeda Customer Support
Hi Chris - I see this older thread has been marked as Resolved but I'm hoping you'll be able to assist me. If I need to open a case with PTC please let me know and I will do so. I'm trying to create a package using this exact example you gave. Step 1, 2, 3 are fine. I can get a session Id, my model Id, and File Upload session id (6219 in my example):
Step 4: I think I am uploading the contents of the file successfully because if I purposely use the wrong MD5 I get an error. I also tried different file sizes. The larger file takes a bit longer. So I think the file is uploading ok. However, the response is not complete, like in your example:
Again, I'm not sure step 4 is completely successful, but I'll move on to step 5. I get a 404 error, resource not found.
Clearly I'm doing something wrong but I can't figure it out. I'm confident the model id is 794 (screenshot below from step 2). Will you please provide me with some guidance?
Thanks, Mike Grudinschi
Mike:
Sorry for the delay. Can you open up a support case on the Portal? We can coordinate testing or a Webex to review this.
Regards,
-Chris
Hi Chris - I've opened a case (13020479). Please contact me directly so we can arrange a webex session. My email is associated with the PTC case.
Thanks, Mike
Did this ever get resolved? I'm having the same problem.
Chris, did the form-data "Choose Files" method work for you? I'm trying it and I cannot see that it is doing anything at all. Not sure if I'm doing something wrong or not.
At the behest of a customer running on 6.5.1, here is a version (in code only) that will work.
6.5.1 did not expose the SoftwarePackageBridge, either via REST or API, so we must use the V1 API NamedPackage to create the package.
There is NO way to do this operation prior to 6.5.1 in any fashion. Call this via Scripto, and provide the FileID and ModelID.
import static com.axeda.sdk.v2.dsl.Bridges.*
import com.axeda.services.v2.*
import com.axeda.sdk.v2.exception.*
// v1 SCM imports
import com.axeda.drm.sdk.scm.*
import com.axeda.drm.sdk.commons.compression.CompressionType
import com.axeda.drm.sdk.Context
import com.axeda.common.sdk.id.Identifier
def fcrit = new FileInfoCriteria(id: 1080918)
def fresult = fileInfoBridge.findOne(fcrit)
InputStream isFile = fileInfoBridge.getFileData("1080918")
def resultString = ''
resultString += "Name: ${fresult.filename}\n"
ctx = Context.getUserContext()
Identifier modelId = new Identifier(6141 as long)
Version v1 = new Version(ctx, 6, 5, 0, 0)
NamedPackage p1 = new NamedPackage(ctx,
"CFK Test Package v1API", modelId, v1,
"Test of the API created package."
)
DownloadInstruction d1 = new DownloadInstruction(".", isFile, fresult.filename,
fresult.filesize, true /*overwrite*/, false /*execute*/,
false /*usercompressed*/, CompressionType.NONE,
true /*device relativepath */
)
p1.addInstruction(d1)
p1.store()
return resultString