Community Tip - You can Bookmark boards, posts or articles that you'd like to access again easily! X
Hi,
I would like to build a form which will allow users to create services without entering the composer.
So is it possible to create services programmatically without using remote services ?
Regards
Solved! Go to Solution.
//
// For this example, we'll have an Math service
// which takes two numbers, and an operation.
// The result will be that operation performed on the two inputs.
//
// We either need an Application Key,
// or user credentials to perform the reads and writes.
// App keys are a little safer.
// In this demo, we'll store it on the Entity as a Property.
var appKey = me.appKey;
//
// The service name needs to be unique and not already in use.
var serviceName = "MyMath";
//
// What are the inputs to the service?
// We'll define them nicely here, but manipulate this object later.
var parameters = {
"op" : "STRING",
"x" : "NUMBER",
"y" : "NUMBER"
};
//
// What datatype does the service return?
// If it's an infotable,
// then you'll also have to specify the data shape
// as part of the resultType's aspect,
// but I won't demonstrate that here.
var output = "NUMBER";
//
// What is the actual service script?
// We'll define it here as an array of lines, and then join them together.
var serviceScript = [
"var result = (function() {",
" switch(op) {",
" case \"add\": return x + y;",
" case \"sub\": return x - y;",
" case \"mult\": return x * y;",
" case \"div\": return x / y;",
" default: return op in Math ? Math[op](x, y) : 0;",
" };",
"})();",
].join("\n");
////////
//
// Let's convert the friendly parameter definition
// into the structure that ThingWorx uses:
var parameterDefinitions = Object.keys(parameters).reduce(function(parameterDefinitions, parameterName, index) {
var parameterType = parameters[parameterName];
parameterDefinitions[parameterName] = {
"name": parameterName,
"aspects": {},
"description": "",
"baseType": parameterType,
"ordinal": index
};
return parameterDefinitions;
}, {});
//
// Now let's set up our service definition and implementation.
var definition = {
"isAllowOverride": false,
"isOpen": false,
"sourceType": "Unknown",
"parameterDefinitions": parameterDefinitions,
"name": serviceName,
"aspects": {
"isAsync": false
},
"isLocalOnly": false,
"description": "",
"isPrivate": false,
"sourceName": "",
"category": "",
"resultType": {
"name": "result",
"aspects": {},
"description": "",
"baseType": output,
"ordinal": 0
}
};
var implementation = {
"name": serviceName,
"description": "",
"handlerName": "Script",
"configurationTables": {
"Script": {
"isMultiRow": false,
"name": "Script",
"description": "Script",
"rows": [{
"code": serviceScript
}],
"ordinal": 0,
"dataShape": {
"fieldDefinitions": {
"code": {
"name": "code",
"aspects": {},
"description": "code",
"baseType": "STRING",
"ordinal": 0
}
}
}
}
}
};
////////
//
// Here are the URLs we'll need in order to make updates.
// You can change the thing name ('ServiceModifier' here)
// to something else.
// If you use credentials instead of an app key,
// then you can remove the appKey parameter here,
// but you'll have to add the username and password
// to the two ContentLoaderFunctions calls.
var url = {
export : "http://127.0.0.1:8080/Thingworx/Things/ServiceModifier?Accept=application/json&appKey="+appKey,
import : "http://127.0.0.1:8080/Thingworx/Things/ServiceModifier?appKey="+appKey
};
//
// We can download the entity to modify as a JSON object.
// Older versions of ThingWorx might not support this.
var config = Resources.ContentLoaderFunctions.GetJSON({
url : url.export,
});
//
// We have to modify both the 'effectiveShape',
// as well as the 'thingShape'.
config.effectiveShape.serviceDefinitions[serviceName] = definition;
config.effectiveShape.serviceImplementations[serviceName] = implementation;
config.thingShape.serviceDefinitions[serviceName] = definition;
config.thingShape.serviceImplementations[serviceName] = implementation;
// Finally, we can push our updates back into ThingWorx.
Resources.ContentLoaderFunctions.PutText({
url : url.export,
content : JSON.stringify(config),
contentType : "application/json",
});
// The end.
there is another thread talking about this
Ok so it is not :/
//
// For this example, we'll have an Math service
// which takes two numbers, and an operation.
// The result will be that operation performed on the two inputs.
//
// We either need an Application Key,
// or user credentials to perform the reads and writes.
// App keys are a little safer.
// In this demo, we'll store it on the Entity as a Property.
var appKey = me.appKey;
//
// The service name needs to be unique and not already in use.
var serviceName = "MyMath";
//
// What are the inputs to the service?
// We'll define them nicely here, but manipulate this object later.
var parameters = {
"op" : "STRING",
"x" : "NUMBER",
"y" : "NUMBER"
};
//
// What datatype does the service return?
// If it's an infotable,
// then you'll also have to specify the data shape
// as part of the resultType's aspect,
// but I won't demonstrate that here.
var output = "NUMBER";
//
// What is the actual service script?
// We'll define it here as an array of lines, and then join them together.
var serviceScript = [
"var result = (function() {",
" switch(op) {",
" case \"add\": return x + y;",
" case \"sub\": return x - y;",
" case \"mult\": return x * y;",
" case \"div\": return x / y;",
" default: return op in Math ? Math[op](x, y) : 0;",
" };",
"})();",
].join("\n");
////////
//
// Let's convert the friendly parameter definition
// into the structure that ThingWorx uses:
var parameterDefinitions = Object.keys(parameters).reduce(function(parameterDefinitions, parameterName, index) {
var parameterType = parameters[parameterName];
parameterDefinitions[parameterName] = {
"name": parameterName,
"aspects": {},
"description": "",
"baseType": parameterType,
"ordinal": index
};
return parameterDefinitions;
}, {});
//
// Now let's set up our service definition and implementation.
var definition = {
"isAllowOverride": false,
"isOpen": false,
"sourceType": "Unknown",
"parameterDefinitions": parameterDefinitions,
"name": serviceName,
"aspects": {
"isAsync": false
},
"isLocalOnly": false,
"description": "",
"isPrivate": false,
"sourceName": "",
"category": "",
"resultType": {
"name": "result",
"aspects": {},
"description": "",
"baseType": output,
"ordinal": 0
}
};
var implementation = {
"name": serviceName,
"description": "",
"handlerName": "Script",
"configurationTables": {
"Script": {
"isMultiRow": false,
"name": "Script",
"description": "Script",
"rows": [{
"code": serviceScript
}],
"ordinal": 0,
"dataShape": {
"fieldDefinitions": {
"code": {
"name": "code",
"aspects": {},
"description": "code",
"baseType": "STRING",
"ordinal": 0
}
}
}
}
}
};
////////
//
// Here are the URLs we'll need in order to make updates.
// You can change the thing name ('ServiceModifier' here)
// to something else.
// If you use credentials instead of an app key,
// then you can remove the appKey parameter here,
// but you'll have to add the username and password
// to the two ContentLoaderFunctions calls.
var url = {
export : "http://127.0.0.1:8080/Thingworx/Things/ServiceModifier?Accept=application/json&appKey="+appKey,
import : "http://127.0.0.1:8080/Thingworx/Things/ServiceModifier?appKey="+appKey
};
//
// We can download the entity to modify as a JSON object.
// Older versions of ThingWorx might not support this.
var config = Resources.ContentLoaderFunctions.GetJSON({
url : url.export,
});
//
// We have to modify both the 'effectiveShape',
// as well as the 'thingShape'.
config.effectiveShape.serviceDefinitions[serviceName] = definition;
config.effectiveShape.serviceImplementations[serviceName] = implementation;
config.thingShape.serviceDefinitions[serviceName] = definition;
config.thingShape.serviceImplementations[serviceName] = implementation;
// Finally, we can push our updates back into ThingWorx.
Resources.ContentLoaderFunctions.PutText({
url : url.export,
content : JSON.stringify(config),
contentType : "application/json",
});
// The end.
Thanks ! It's a perfect explanation and it works.