Skip to main content

Services


Services

Services are configured separately and independently from each UI component, please refer to Understanding the graph model for better understanding of the high level solution and how services fits the overall picture.

Transformers - Parsing service data

To populate the client data store (graph), a transformer is applied. The transformer parses the service response payload into nodes and edges and populates the graph data store. To facilitate standard and documented services, built-in transformers are included. It is possible to register you own transformers to parse any undocumented or external service into the data store, and use the UI components just as usual for any data. See Resource deployment for detail on how to deploy plugin code. Refer to Plugin code extensions for transformer coding details. To use an extension point it out in your widget definition Widget.

The framework comes with several built-in transformers. The transformer is defined using the transformer property.

JSONata configurable transformer

To enable parsing of most payload formats a highly configurable jsonata transformer is included. JSONata is very versatile and could be used for most cases to avoid writing custom parsing code.

https://docs.jsonata.org/

info

JSONata is a lightweight query and transformation language for JSON data. Inspired by the 'location path' semantics of XPath 3.1, it allows sophisticated queries to be expressed in a compact and intuitive notation. A rich complement of built in operators and functions is provided for manipulating and combining extracted data, and the results of queries can be formatted into any JSON output structure using familiar JSON object and array syntax. Coupled with the facility to create user defined functions, advanced expressions can be built to tackle any JSON query and transformation task.

JSONata syntax can be tricky, use of AI is recommended (https://claude.ai/ is a great option). The result can be iterated and verified in https://try.jsonata.org/.

Your JSONata expression must produce the following format to be accepted by the graph:

[
{
"id" : "nodeID",
"type" : "nodeType",
...additional properties goes here
},
{
"id" : "edgeID",
"type" : "edgeType",
"source" : "nodeID",
"target" : "nodeID",
...additional properties goes here
}
]

Example jsonata transformer configuration (see transformer.inputs.expression)

"dslibLibraryClassifiableClasses" : {
"description": "Expands a libaray onto subclasses to which the user has Classify Access",
"uri": "/resources/v1/modeler/dslib/dslib:Library/{{contextId}}?$mask=dslib:ExpandClassifiableClassesMask",
"transformer": {
"name": "jsonata",
"inputs": {
"expression": "( $f := function($n, $p) { $n.member.( $c := $; $o := $sift($c, function($v, $k) { $k != 'ChildClasses' }); $r := $p ? [ $o, { 'id': $p & '_ChildClasses_' & $c.id, 'type': 'ChildClasses', 'source': $p, 'target': $c.id } ] : [ $o ]; $append($r, $f($c.ChildClasses, $c.id)) ) }; $f($, null) )"
}
}
}
Example prompt to generte JSONata
Create a JSONata (http://docs.jsonata.org) expression that transforms my 'Example Payload' so that it converts all members into the 'Target Format'.
- Include all properties except ChildClasses
- Use single quotes
- Make it a one liner

Target format:
'''
[
{
"id" : "nodeID",
"type" : "nodeType",
...additional properties goes here
},
{
"id" : "<parentNodeID>_ChildClasses_<nodeID>",
"type" : "ChildClasses",
"source" : "parentNodeID",
"target" : "nodeID",
...additional properties goes here
}
]
'''

Example Payload:
'''
{
"totalItems": 1,
"member": [
{
"id": "BCA5C3EC746500006231E6320002BA22",
"name": "Library-R1132101359392-00000001",
"title": "Electronic components",
"libraryUsage": "Definition",
"description": "",
"type": "General Library",
"modified": "11\/5\/2025 8:48:55 AM",
"created": "3\/16\/2022 1:29:22 PM",
"revision": "-",
"state": "Active",
"owner": "Philippe RINERO",
"organization": "Company Name",
"collabspace": "Common Space",
"ChildClasses": {
"totalItems": 1,
"member": [
{
"id": "BCA5C3EC746500006231E6550010F302",
"name": "Class-R1132101359392-00000001",
"title": "Passive",
"classUsage": "Definition",
"description": "",
"type": "General Class",
"state": "Active",
"modified": "11\/5\/2025 8:48:55 AM",
"created": "3\/16\/2022 1:29:57 PM",
"revision": "BCA5C3EC746500006231E6320002BA22",
"owner": "Philippe RINERO",
"organization": "Company Name",
"collabspace": "Common Space",
"ChildClasses": {
"totalItems": 1,
"member": [
{
"id": "BCA5C3EC746500006231E7D10005BD88",
"name": "Class-R1132101359392-00000002",
"title": "Resistor",
"classUsage": "Definition",
"description": "",
"type": "General Class",
"state": "Active",
"modified": "11\/5\/2025 8:48:55 AM",
"created": "3\/16\/2022 1:36:17 PM",
"revision": "BCA5C3EC746500006231E6550010F302",
"owner": "Philippe RINERO",
"organization": "Company Name",
"collabspace": "Common Space"
}
]
}
}
]
}
}
],
"nlsLabel": {
"id": "Id",
"name": "Name",
"title": "Title",
"libraryUsage": "Purpose",
"classUsage": "Purpose",
"description": "Description",
"type": "Type",
"modified": "Modification Date",
"created": "Creation Date",
"revision": "Revision",
"state": "State",
"owner": "Owner"
}
}
'''

AI JSONata response (after 2 iterations asking it to fix a syntax error 't.apply is not a function' and to improve performance**)**

$reduce($map(**.member, function($n){$append([$sift($n, function($v,$k){$k!='ChildClasses'})], $n.revision!='-' ? [{'id':$n.revision&'_ChildClasses_'&$n.id,'type':'ChildClasses','source':$n.revision,'target':$n.id}] : [])}), $append, [])

Chaining services

service Aservice Bservice C

It is quite common that data is a combination of multiple chained services e.g. first call a service get all the instances (relationships), then based on that result get all references (objects). To chain services use the services property. A chained service will use the eles that the transformer of the parent service returns.

"services": {
"engItemChangeControl": {
"uri": "/resources/v1/modeler/dseng/dseng:EngItem/{{contextId}}/dslc:changeControl",
...
"services": ["changeAction"] // Chain call
},
"changeAction" : {
"uri": "/resources/v1/modeler/dslc/changeaction/{{contextId}}",
...
}
}

Macros

All service configuration support macros. A macros is typically a physical id or similar. A macro is identified with double curly brackets e.g. {{contextId}}.

KeyDescription
contextIdPhysical id of the dropped context object or the id property of the related node (e.g. for column or chained data)
parentContextIdPhysical id of the parent node of current in case structure
securityContextTODO
select:<property>select a property off the node
"exampleUsingMacros" : {
"uri": "/resources/issues/batch?tenant={{tenant}}&xrequestedwith=xmlhttprequest",
...
"payload": {
"requests": [
{
...
"url": "resources/issues/{{contextId}}/related",
"body": {
"physicalId": "{{contextId}}",
}
}
]
}
}

Caching (performance)

This configuration based on Caching mechanism. Caching is a technique used to store data temporarily so that it doesn't need to be fetched again from the original source every time it's requested. This can help improve performance and reduce the load on your backend systems, as repeated requests for the same data don't need to make another call to the server.

A common use case for caching is to avoid making repeated calls to the server within a short period. For example, if you are requesting a list of data multiple times within a few minutes, caching the response ensures that you don't overload the server with duplicate requests. The system will use the cached data instead of querying the server again for the same information.

  • Caching helps improve performance by storing data temporarily.
  • If real-time updates are not critical, cache the data to avoid unnecessary calls to the server.
  • Disabling caching ensures fresh data but might reduce performance due to more frequent server calls.
"defaultServiceParams": {
"enableCache": false,
"cacheTimelimit": 1
}
Prop NameDescriptionData TypeRequiredExample
enableCacheEnables caching if true.booleannofalse
cacheTimelimitCache duration in minutes.numberno1

Inherit service templates

service (based on)? service TEMPLATE

One service definition can be inherited to another using inheritedServiceName . Inheritance allows to efficiently maintain small variations in how to call a service.

"template" : {
"uri": "/resources/v1/modeler/dsiss/issue/{{contextId}}",
...
},
"inheritExample" : {
"inheritedServiceName": "template",
"uri" : "/resources/v1/modeler/dsiss/issue/{{contextId}}?$mask=example" // Inherits and overrides a prop
}

Service configuration properties

Prop NameDescriptionData TypeRequiredExample
absoluteURITreats URI as absolute if true.booleannotrue
addCSRFTokenAdds CSRF token for security if true.booleannotrue
conditionDefines a where clause to control for what data to call the service. e.g. only call for change approval data for nodes in a certain state.objectno"condition": {"node": "[type='VPMReference']"s}
contextParamsContext variables for the service.array stringno["contextId"]
datasetsLinks to datasets (custom extension). (See more)stringno"changeRequestData"
excludePropsFromParentInherit properties from the parent service while excluding a specified list of properties.array stringno["uri"]
headersCustom HTTP headers.objectno{"Content-Type": "application/json"}
inheritedServiceNameInherit properties from another service into the current service.stringno"baseService"
localizationLocalized data settings.objectno{"lang": "en"}
methodHTTP method (e.g., GET, PATCH, POST). Defaults to GET.stringno"GET"
multipleFetchTrue in case form data submit and perform some multiple service call iteratively before service chain call.booleanno"multipleFetch":true
payloadThe payload content to passed with POST & PATCH requests. All properties and below structure wil be stringified and includede. The following MACROS are evaluated ['{{contextId}}',..]. For in-cell edit services, payload can use '{{FIELD_IDENTIFIER}}' and '{{FIELD_VALUE}}': FIELD_IDENTIFIER is resolved from column.edit.editSelect (or fallback column data select) and FIELD_VALUE is resolved from the edited cell value. Example: { '{{FIELD_IDENTIFIER}}': '{{FIELD_VALUE}}', 'cestamp': '{{cestamp}}' }.objectno{"title": "{{title}}"}
preRequestTransformerPre-request payload or context data transformer. This is used in chain service input used as payload of second service.stringno"updateIssueTransformer"
relationTypeWhen a service do not include edge (relation) detail this value would be used as edge type.stringno"resolvedBy"
removeNonEditedFieldsStrips unchanged fields if true.booleannotrue
runOnceCall the service just once with the same arguments for that view. Useful to improve performance when the same data is present multiple times in the same view e.g. recurring person data such as owner in a table, if true.booleannotrue
serviceDomainDomain scope for the service.stringno"modeler"
serviceCallerCustom caller for the service.stringno"customCaller"
serviceCallerPropsOptions for the custom caller.objectno{"timeout": 5000}
servicesThis props used to acheive chaining call another service once current complete.array stringnoservices:["fetchIssueDetails"]
securityContextHeaderPatternSecurity context for authentication.stringno"ctx::VPLMProjectLeader.Company Name.Common Space"
skipGraphSaveSkips service response to persist in graph true.booleannotrue
shouldBeanPersistSet to true if the data is added to the graph node and stays in sync with the bean after the service call, if true.booleannotrue
transformerA built in or plugin transformer responsible for parsing the service response to data store.string objectyes{"name":"jsonata","inputs":{"expression":"( $f := function($n, $p) { $n.member.( $c := $; $o := $sift($c, function($v, $k) { $k != 'ChildClasses' }); $r := $p ? [ $o, { 'id': $p & 'ChildClasses' & $c.id, 'type': 'ChildClasses', 'source': $p, 'target': $c.id } ] : [ $o ]; $append($r, $f($c.ChildClasses, $c.id)) ) }; $f($, null) )"}}
uriAPI endpoint with optional macros.stringyes"/resources/issues"/{{contextId}}
uriParamsOptional URI query params. Object keys override matching query params already defined in uri while preserving any other params from uri.object (string values)no{"$top": "50", "$mask": "dseng:EngItemMask.Default"}
validForRestricts service to specific object types.stringno"Issue"
useRootContextIdsSet to true use context node as context id or parent Id in some special service callm.booleannotrue

3DEXPERIENCE services

DS public service API

Best practice is using the documented and supported services listed on Dassault Systemes Developer Assistance (3ds.com). Widget configuration based on documented services is most stable over time and require the least possible maintenance.

DS undocumented service API

There are other undocumented platform services used by many of the OOTB Widget apps. Using such service could be beneficial and enable better performance or other capabilities, with the risk of change and more maintenance over time. It is possible to configure such services, jsonata can be used to parse the payload data to the data store (graph).

Authentication

All service calls uses the 3DEXPERIENCE platform authenticated API's.

Built in for 3DEXPERIENCE

To enable quick widget configuration and have standard 3DEXPERIENCE service data loaded into the graph, transformers to parse service data and complete service configurations are included. Many of the documented DS public API services are included in the built in common service configurations. The built in service configurations are found in the admin UI, from the online studio and is accessible by the AI assistant. Configurations can be included using widget the extensions property.

3DEXPERIENCE transformers

TransformerDescriptionExample
6wDesign to parse and transform response from services classified as 6w."relatedDocs" : { "description": "Get all documents realated to a VPMReference", "uri": "/resources/v1/modeler/documents/parentId/{{contextId}}?parentRelName=SpecificationDocument,Reference Document", "transformer": "6w", "relationType": "Document" }
corpusDesign to parse and transform response from services classified as corpus."mfgItems" : { "uri": "/resources/v1/modeler/dsmfg/dsmfg:MfgItem/search?$top=1000", "transformer": "corpus" }
cvservletDesign to parse and transform response from services classified as 6w."getFiltersDetailsFromIds": { "uri": "/resources/FilterBIAPI/Filter/getFiltersFromIds?xrequestedwith=xmlhttprequest", "method": "POST", "securityContextHeaderPattern": "ctx::{{securityContext}}", "addCSRFToken": true, "payload": ["{{contextId}}"], "transformer": "cvservlet" }
locateTODO
corpusgenericTODO
jsonataHighly configurable transformer that evaluates a JSONata expression (transformer.inputs.expression) and maps response payloads into graph nodes and edges."dslibLibraryClassifiableClasses" : { "description": "Expands a libaray onto subclasses to which the user has Classify Access", "uri": "/resources/v1/modeler/dslib/dslib:Library/{{contextId}}?$mask=dslib:ExpandClassifiableClassesMask", "transformer": { "name": "jsonata", "inputs": { "expression": "( $f := function($n, $p) { $n.member.( $c := $; $o := $sift($c, function($v, $k) { $k != 'ChildClasses' }); $r := $p ? [ $o, { 'id': $p & 'ChildClasses' & $c.id, 'type': 'ChildClasses', 'source': $p, 'target': $c.id } ] : [ $o ]; $append($r, $f($c.ChildClasses, $c.id)) ) }; $f($, null) )" } } }