Web Services Gateway Web API follows REST guidelines and exposes all information as resources. Each resource object can only be an instance of a certain class. Class describes properties of instances, and are types of resources that are logically grouped into services. Each service is described by a schema that is simply a list of classes in the service. The following list summarizes the main terms used in this reference:
Schema (service) examples:
Bentley Web Services Gateway Web API is dynamic by design. Names of schemas, classes and properties are used in constructing the exposed URLs.
Please visit the API Explorer tool delivered with each Bentley Web Services deployment, found at https://localhost/ws.
Web Services Gateway Web API can expose any type of repository. Repository support is based on a dynamic plugin infrastructure, and can be extended and customized. Standard installation can deliver plugins like Bentley ProjectWise or Bentley eB Insight. It is possible to add support to other repository types by implementing the custom plugin. As a result, the URLs exposed by Web Service Gateway Web API can differ depending on:
As all information in Web API is modeled as instances of some class, the same JSON format is returned for all requests. Depending on the request type, the response in JSON may slightly differ in the number of properties or presence of linked instances. However, the general parts remain the same.
The 2.0 and later JSON format is not compatible with 1.x series responses, the main changes being:
Instances with one relationship and one related instance (relationship and related instances are present only if specifically requested using the $select statement):
{
"instances": [
{
"instanceId": "{instanceId}",
"className": "{class}",
"schemaName": "{schema}",
"eTag": "Value_Of_ETag",
"properties": {
"property1": "Value_Of_Property1",
"property2": "Value_Of_Property2",
"propertyN": "Value_Of_PropertyN"
},
"relationshipInstances": [
{
"instanceId": "{instanceId}",
"className": "{class}",
"schemaName": "{schema}",
"eTag": "Value_Of_ETag",
"direction": "forward",
"properties": {},
"relatedInstance": {
"instanceId": "{relatedInstanceId}",
"className": "{class}",
"schemaName": "{schema}",
"eTag": "Value_Of_ETag",
"properties": {
"relProperty1": "Value_Of_RelProperty1",
"relProperty2": "Value_Of_RelProperty2",
"relPropertyN": "Value_Of_RelPropertyN"
}
}
}
]
}
]
}
For example:
{
"instances": [
{
"instanceId": "8b1f8955-a5fc-463e-97a6-23479b5512b7",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "hzTGd1g/0yjMX2iAtIL0OeAN9fA=",
"properties": {
"FileName": "img1.jpg",
"MimeType": "raster",
"CreateTime": "2014-12-09T11:54:02.63Z",
"UpdateTime": "2015-01-23T13:29:12.2Z",
"FileUpdateTime": "2014-12-09T11:54:02.85Z",
"CreatedById": 14,
"UpdatedById": 14,
"FileSize": "849860",
"IsLatest": true,
"Description": "img.changeset.013",
"Version": "",
"Name": "img1",
"IsLocked": false,
"ParentGuid": "b2f5e500-c6d4-4dac-8036-15e2f0b19f7f",
"FileUpdatedById": 14,
"EnvironmentId": 101
},
"relationshipInstances": [
{
"instanceId": "",
"className": "DocumentEnvironment",
"schemaName": "PW_WSG",
"eTag": "vD4ORP/4zxAdzlzmhDfYGMb7DdQ=",
"direction": "forward",
"properties": {},
"relatedInstance": {
"instanceId": "661d2cef-d777-4396-8818-bab51edef4d8",
"className": "Env_101",
"schemaName": "PW_WSG_Dynamic",
"eTag": "UEXGpvsPWMgZUpUB5U9G93pq/bQ=",
"properties": {
"Color": "Red",
"Count": 1
}
}
}
]
}
]
}
Despite the fact that exact URLs exposed by Web Services Gateway Web API can vary between deployments, they all follow the same format. The generic URL format is:
v2.5/{GlobalSchema}/{GlobalInstanceId}/...
Where GlobalInstanceId is the ID of the default class in GlobalShema. The following global schemas are delivered with the default installation:
Example:
GET v2.5/Repositories/Bentley.PW--PW/...
All services work in the same style; they expose classes and API allows operations with instances of those classes. All the features described in this document are valid for the Repository and all exposed services.
In addition to global services (Repositories, Plugins, Policies, MetaSchema), each repository exposes “internal” services described by schemas. The URL format is:
v2.5/Repositories/{repositoryId}/{schema}/...
Example:
GET v2.5/Repositories/Bentley.PW--PW/Navigation
By default, Web Services Gateway Web API exposes a set of standard in-repository service schemas (Policies, Views, Contents, Navigation, MetaSchema) and helper schemas (Bentley_Standard_Classes, DataSourceSpecification, EditorCustomAttributes, Bentley_Standard_CustomAttributes). The schemas describing a persistence service are unique for each repository. It is common for repositories to expose more than one schema for grouping and separating domain objects. For example, the standard Bentley ProjectWise repository exposes schema named PW_WSG.
Retrieves a list of repositories from all registered plugins.
Since: 2.0
Response example:
{
"instances": [
{
"instanceId": "Bentley.eB--MyWarehouse",
"className": "RepositoryIdentifier",
"schemaName": "Repositories",
"eTag": "uBXbj6nWff66M53yGm59yn72WIQ=",
"properties":
{
"ECPluginID": "Bentley.eB",
"Location": "MyWarehouse",
"DisplayLabel": "MyWarehouse",
"Description": "MyWarehouse"
}
},
{
"instanceId": "Bentley.PW--PW",
"className": "RepositoryIdentifier",
"schemaName": "Repositories",
"eTag": "DlB30QqHqT7vokR9tL1/n+IST+g=",
"properties":
{
"ECPluginID": "Bentley.PW",
"Location": "PW",
"DisplayLabel": "PW",
"Description": "PW"
}
}
]
}
Usage example
$.get(
"https://localhost/ws/v2.5/Repositories",
function(data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].id);
}
},
"json"
);
Retrieves a list of repositories from all registered plugins with an applied filter. Please refer to the Instance querying options for a full OData query description and examples.
Since: 2.0
Parameters
propertyName |
Optional. Property name to filter by. Must be specified together with propertyValue |
propertyValue |
Optional. Property value to filter by. Must be specified together with propertyName |
Response example
{
"instances": [
{
"instanceId": "Bentley.eB--MyWarehouse",
"className": "RepositoryIdentifier",
"schemaName": "Repositories",
"eTag": "uBXbj6nWff66M53yGm59yn72WIQ=",
"properties":
{
"ECPluginID": "Bentley.eB",
"Location": "MyWarehouse",
"DisplayLabel": "MyWarehouse",
"Description": "MyWarehouse"
}
}
]
}
Usage example
$.get( "https://localhost/ws/v2.5/Repositories/?filter=Location+eq+%27MyWarehouse%27",
function(data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].id);
}
},
"json");
);
Navigation is a presentation service.
Exposed schemas: Navigation
Exposed classes: NavNode
The Navigation service uses NavNode class instances to represent a hierarchal tree-like view of the repository. NavNode instance represents a node in the navigation tree and can be related to an instance of any other domain class, for example, a folder or document. The relationship is not mandatory; it is legal to have virtual NavNode instances that have no corresponding domain class instance (for example, a tree node for grouping modified documents from last month). Each NavNode instance contains properties with display and identification information of related domain class instances, if any.
Retrieves root Navigation tree nodes.
Since: 2.0
Parameters:
repositoryId |
Required. The ID of the repository against which to authenticate. |
Response example
{
"instances": [
{
"instanceId": "ECObjects--PW_WSG-Project-8b674542-442b-430c-ba1b-127ba4ce8350",
"className": "NavNode",
"schemaName": "Navigation",
"eTag": "lDJ/l6UbHcFDeRFJzm9VWqMnY5w=",
"properties": {
"Key_TypeSystem": "ECObjects",
"Key_SchemaName": "PW_WSG",
"Key_ClassName": "Project",
"Key_InstanceId": "8b674542-442b-430c-ba1b-127ba4ce8350",
"Label": "dmsSystem",
"Description": "",
"CollapsedImageID": "",
"ExpandedImageID": "",
"HasChildren": false,
"Selectable": true,
"IsEditable": false,
"IsFileBacked": false,
"IsCheckBoxEnabled": true,
"IsCheckBoxVisible": false,
"IsChecked": false,
"IsDragEnabled": true
}
},
{
"instanceId": "ECObjects--PW_WSG-Project-947ce29e-fc26-493b-9606-53b8f61b1b1b",
"className": "NavNode",
"schemaName": "Navigation",
"eTag": "SKOTh827nTJTkeKKRjab5r3z3Dg=",
"properties": {
"Key_TypeSystem": "ECObjects",
"Key_SchemaName": "PW_WSG",
"Key_ClassName": "Project",
"Key_InstanceId": "947ce29e-fc26-493b-9606-53b8f61b1b1b",
"Label": "LL84 Coordinate system_whole world",
"Description": "",
"CollapsedImageID": "",
"ExpandedImageID": "",
"HasChildren": false,
"Selectable": true,
"IsEditable": false,
"IsFileBacked": false,
"IsCheckBoxEnabled": true,
"IsCheckBoxVisible": false,
"IsChecked": false,
"IsDragEnabled": true
}
}
]
}
Retrieves the child nodes of a specified parent node.
Since: 2.0
Parameters:
repositoryId |
Required. The ID of the repository against which to authenticate. |
parentNodeId |
Required. The ID of parent NavNode instance. |
Response example
{
"instances": [
{
"instanceId": "ECObjects--PW_WSG-Project-bb281b1c-09a2-46ad-bc4e-e6c2889e267a",
"className": "NavNode",
"schemaName": "Navigation",
"eTag": "YZIiza1Zn95GOiRI7l7rc41dIaw=",
"properties": {
"Key_TypeSystem": "ECObjects",
"Key_SchemaName": "PW_WSG",
"Key_ClassName": "Project",
"Key_InstanceId": "bb281b1c-09a2-46ad-bc4e-e6c2889e267a",
"Label": "components",
"Description": "",
"CollapsedImageID": "",
"ExpandedImageID": "",
"HasChildren": false,
"Selectable": true,
"IsEditable": false,
"IsFileBacked": false,
"IsCheckBoxEnabled": true,
"IsCheckBoxVisible": false,
"IsChecked": false,
"IsDragEnabled": true
}
},
{
"instanceId": "ECObjects--PW_WSG-Project-2cd6700e-37bc-41ed-bd5b-3c01ae29562c",
"className": "NavNode",
"schemaName": "Navigation",
"eTag": "58EOOBBQPij+UQ7BfwNbErU7QtY=",
"properties": {
"Key_TypeSystem": "ECObjects",
"Key_SchemaName": "PW_WSG",
"Key_ClassName": "Project",
"Key_InstanceId": "2cd6700e-37bc-41ed-bd5b-3c01ae29562c",
"Label": "Spatial",
"Description": "",
"CollapsedImageID": "",
"ExpandedImageID": "",
"HasChildren": false,
"Selectable": true,
"IsEditable": false,
"IsFileBacked": false,
"IsCheckBoxEnabled": true,
"IsCheckBoxVisible": false,
"IsChecked": false,
"IsDragEnabled": true
}
}
]
}
Retrieves root Navigation tree nodes with a filter (a filter can also be applied when retrieving child nodes of specific NavNode). Please refer to Instance querying options for the full OData query description and examples.
Since: 2.0
Parameters:
repositoryId |
Required. The ID of the repository against which to authenticate. |
propertyName |
Optional. Property name to filter by. Must be specified together with propertyValue |
propertyValue |
Optional. Property value to filter by. Must be specified together with propertyName |
Response example
{
"instances": [
{
"instanceId": "ECObjects--PW_WSG-Project-8b674542-442b-430c-ba1b-127ba4ce8350",
"className": "NavNode",
"schemaName": "Navigation",
"eTag": "lDJ/l6UbHcFDeRFJzm9VWqMnY5w=",
"properties": {
"Key_TypeSystem": "ECObjects",
"Key_SchemaName": "PW_WSG",
"Key_ClassName": "Project",
"Key_InstanceId": "8b674542-442b-430c-ba1b-127ba4ce8350",
"Label": "dmsSystem",
"Description": "",
"CollapsedImageID": "",
"ExpandedImageID": "",
"HasChildren": false,
"Selectable": true,
"IsEditable": false,
"IsFileBacked": false,
"IsCheckBoxEnabled": true,
"IsCheckBoxVisible": false,
"IsChecked": false,
"IsDragEnabled": true
}
},
{
"instanceId": "ECObjects--PW_WSG-Project-947ce29e-fc26-493b-9606-53b8f61b1b1b",
"className": "NavNode",
"schemaName": "Navigation",
"eTag": "DSKOTh827nTJTkeKKRjab5r3z3Dg=A",
"properties": {
"Key_TypeSystem": "ECObjects",
"Key_SchemaName": "PW_WSG",
"Key_ClassName": "Project",
"Key_InstanceId": "947ce29e-fc26-493b-9606-53b8f61b1b1b",
"Label": "LL84 Coordinate system_whole world",
"Description": "",
"CollapsedImageID": "",
"ExpandedImageID": "",
"HasChildren": false,
"Selectable": true,
"IsEditable": false,
"IsFileBacked": false,
"IsCheckBoxEnabled": true,
"IsCheckBoxVisible": false,
"IsChecked": false,
"IsDragEnabled": true
}
}
]
}
Meta schema service allows access to information about available schemas, classes, properties both in a global and repository scope.
Exposed schemas: MetaSchema
Exposed classes: ECSchemaDef, ECClassDef, ECPropertyDef
All GET requests support additional parameters for filtering found instances. Please refer to Instance querying options for the full OData query description and examples.
Retrieves all the schemas available in the repository. Results are represented as instances of ECSchemaDef class.
Since: 2.0
Response example
{
"instances": [
{
"instanceId": "N~3AMetaSchema.02.00",
"className": "ECSchemaDef",
"schemaName": "MetaSchema",
"eTag": "Lmde3qNdVcK/kuSvCMxnq6Y1qBw=",
"properties": {
"Name": "MetaSchema",
"DisplayLabel": "MetaSchema",
"NameSpacePrefix": "ms",
"Description": null,
"VersionMajor": 2,
"VersionMinor": 0
}
},
{
"instanceId": "N~3ABentley_Standard_Classes.01.00",
"className": "ECSchemaDef",
"schemaName": "MetaSchema",
"eTag": "s0iqEEQ+2h2hXsk0Gj2pahh9xDg=",
"properties": {
"Name": "Bentley_Standard_Classes",
"DisplayLabel": "Bentley Standard Classes",
"NameSpacePrefix": "bsm",
"Description": "Bentley Standard Classes",
"VersionMajor": 1,
"VersionMinor": 0
}
},
...
]
}
Imports a new schema into the repository. Requests should contain an ECSchemaDef instance with the schema file attached. All connections are updated instantly; IIS restart is not required.
Please refer to POST v2.5/Repositories/{repositoryId}/{schema}/{class} request description for more information and examples.
Since: 2.3
Retrieves all the classes from every schema available in the repository. Results are represented as instances of ECClassDef class.
Since: 2.0
Response example
{
"instances": [
{
"instanceId": "N~3ANavigation.01.00~3ANavNode",
"className": "ECClassDef",
"schemaName": "MetaSchema",
"eTag": "vkArHlzFcXldn2wkfAZPtdJSzCw=",
"properties": {
"Name": "NavNode",
"DisplayLabel": "Navigation Node",
"Schema": "Navigation.01.00",
"Description": null,
"IsStruct": false,
"IsCustomAttributeClass": false,
"IsDomainClass": true,
"HasBaseClasses": false,
"IsRelationshipClass": false,
"BaseClasses": [ ]
}
},
{
"instanceId": "N~3ABentley_Standard_CustomAttributes.01.11~3AAllowDuplicateLocalizedValues",
"className": "ECClassDef",
"schemaName": "MetaSchema",
"eTag": "OXIh7uxwiS05VfXTbgiZA1gbscU=",
"properties": {
"Name": "AllowDuplicateLocalizedValues",
"DisplayLabel": "Allow duplicate localized values",
"Schema": "Bentley_Standard_CustomAttributes.01.11",
"Description": "Keeps the localizable values from this element from being combined with those from another element if duplication occurs.",
"IsStruct": false,
"IsCustomAttributeClass": true,
"IsDomainClass": false,
"HasBaseClasses": false,
"IsRelationshipClass": false,
"BaseClasses": [ ]
}
},
...
]
}
Retrieves all the classes in a specific schema. Please refer to Instance querying options for the full OData query description and examples.
Since: 2.0
Response example
{
"instances": [
{
"instanceId": "N~3ABentley_Standard_CustomAttributes.01.11~3AAllowDuplicateLocalizedValues",
"className": "ECClassDef",
"schemaName": "MetaSchema",
"eTag": "OXIh7uxwiS05VfXTbgiZA1gbscU=",
"properties": {
"Name": "AllowDuplicateLocalizedValues",
"DisplayLabel": "Allow duplicate localized values",
"Schema": "Bentley_Standard_CustomAttributes.01.11",
"Description": "Keeps the localizable values from this element from being combined with those from another element if duplication occurs.",
"IsStruct": false,
"IsCustomAttributeClass": true,
"IsDomainClass": false,
"HasBaseClasses": false,
"IsRelationshipClass": false,
"BaseClasses": [ ]
}
},
{
"instanceId": "N~3ABentley_Standard_CustomAttributes.01.11~3APropertyReferenceProperties",
"className": "ECClassDef",
"schemaName": "MetaSchema",
"eTag": "+9NiOogkTLs1D2Shzwfz70PvwoQ=",
"properties": {
"Name": "PropertyReferenceProperties",
"DisplayLabel": "Property reference properties",
"Schema": "Bentley_Standard_CustomAttributes.01.11",
"Description": "Applied to a custom attribute class defiition to indicate which string properties refer to a property in the class.",
"IsStruct": false,
"IsCustomAttributeClass": true,
"IsDomainClass": false,
"HasBaseClasses": false,
"IsRelationshipClass": false,
"BaseClasses": [ ]
}
},
...
]
}
Persistence service implements access to all domain objects exposed from the repository.
Exposed schemas: multiple repository specific schemas. Please use the MetaSchema service to query for schemas available in the repository.
Exposed classes: multiple repository specific (custom) classes in each of the schemas. Please use the MetaSchema service to query for classes available in the repository.
Retrieves a list of all instances in the class.
Since: 2.0
Parameters:
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing class to be queried. |
class |
Required. The class name of the instances to be retrieved. |
Response example
{
"instances": [
{
"instanceId": "6b7d6991-82ae-4060-b1f3-d810d270e127",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "NLUKmsIl2eRij9C+fsGttWI51cA=",
"properties": {
"FileName": "concatenate.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:09:58.29Z",
"UpdateTime": "2014-08-22T21:01:09.257Z",
"FileUpdateTime": "2014-08-22T21:01:09.257Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "8775",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "concatenate.oxygenicity",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
},
{
"instanceId": "100e8c87-9585-4d5f-8c25-e327f8e1d74e",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "DjBREV7zWcqXWaBYFLI+xKdbu/c=",
"properties": {
"FileName": "furrily.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:10:42.697Z",
"UpdateTime": "2014-08-22T21:02:30.357Z",
"FileUpdateTime": "2014-08-22T21:02:30.357Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "526",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "furrily.supersensual",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
}
]
}
Usage example
$.get("https://localhost/ws/v2.5/Repositories/Bentley.PW--PW/PW_WSG/Document/",
function(data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].id);
}
},
"json");
Retrieves a specific instance of the class.
Since: 2.0
Parameters:
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing class to be queried. |
class |
Required. The class name of the instance to be retrieved. |
instanceId |
Optional. The ID of the instance to be retrieved. |
Response example
{
"instances": [
{
"instanceId": "6b7d6991-82ae-4060-b1f3-d810d270e127",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "NLUKmsIl2eRij9C+fsGttWI51cA=",
"properties": {
"FileName": "concatenate.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:09:58.29Z",
"UpdateTime": "2014-08-22T21:01:09.257Z",
"FileUpdateTime": "2014-08-22T21:01:09.257Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "8775",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "concatenate.oxygenicity",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
}
]
}
Usage example
$.get("https://localhost/ws/v2.5/Repositories/Bentley.PW--PW/PW_WSG/Document/6b7d6991-82ae-4060-b1f3-d810d270e127/",
function(data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].id);
}
},
"json" );
Retrieves a list of instances with a filter applied. Please refer to Instance querying options for the full OData query description and examples.
Since: 2.0
Parameters:
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing class to be queried. |
class |
Required. The class name of the instances to be retrieved. |
propertyName |
Optional. Property name to filter by. Must be specified together with propertyValue |
propertyValue |
Optional. Property value to filter by. Must be specified together with propertyName |
Response example
{
"instances": [
{
"instanceId": "6b7d6991-82ae-4060-b1f3-d810d270e127",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "NLUKmsIl2eRij9C+fsGttWI51cA=",
"properties": {
"FileName": "concatenate.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:09:58.29Z",
"UpdateTime": "2014-08-22T21:01:09.257Z",
"FileUpdateTime": "2014-08-22T21:01:09.257Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "8775",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "concatenate.oxygenicity",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
},
{
"instanceId": "100e8c87-9585-4d5f-8c25-e327f8e1d74e",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "DjBREV7zWcqXWaBYFLI+xKdbu/c=",
"properties": {
"FileName": "furrily.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:10:42.697Z",
"UpdateTime": "2014-08-22T21:02:30.357Z",
"FileUpdateTime": "2014-08-22T21:02:30.357Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "526",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "furrily.supersensual",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
}
]
}
Usage example
$.get(
"https://localhost/ws/v2.5/Repositories/Bentley.PW--PW/PW_WSG/Document/?filter=FileName+like+%27*.json%27",
function(data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].id);
}
},
"json"
);
Retrieves a specific instance with selected properties only. Note: If a URL specifies the {instanceId}, only $select can be used from the list of available query options of OData queries. Please refer to Instance querying options for the full OData query description and examples.
Since: 2.0
Parameters:
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing class to be queried. |
class |
Required. The class name of the instance to be retrieved. |
propertyName1 |
Optional. Property name to select in the retrieved result. |
propertyNameN |
Optional. Property name to select in the retrieved result. |
Response example
{
"instances": [
{
"instanceId": "6b7d6991-82ae-4060-b1f3-d810d270e127",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "NLUKmsIl2eRij9C+fsGttWI51cA=",
"properties": {
"propertyName1": "concatenate.json",
"propertyNameN": "unknown",
}
}
]
}
Usage example
$.get("https://localhost/ws/v2.5/Repositories/Bentley.PW--PW/PW_WSG/Document/6b7d6991-82ae-4060-b1f3-d810d270e127/",
function(data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].id);
}
},
"json"
);
Retrieves a list of all instances in class1 related to the instance with an instanceId of class2 (for example, all documents in specific folder). Please refer to Relationships and related classes for a full description about relationships.
Since: 2.0
Parameters:
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema1 |
Required. The schema name of the class1. |
class1 |
Required. The class name of the instances to be retrieved. |
instanceId |
Required. The ID of the linked class2 instance. |
Notes on the parameters:
'schema1' parameter is optional if 'relationshipClass' and 'class1' belongs to the same schema.
'schema2' parameter is optional if the 'class2' belongs to the same schema as 'class1'.
'{schema1}.{relationshipClass}-{direction}' parameter is optional if there is only a single relationship class between 'class1' and 'class2'.
Response example
{
"instances": [
{
"instanceId": "6b7d6991-82ae-4060-b1f3-d810d270e127",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "NLUKmsIl2eRij9C+fsGttWI51cA=",
"properties": {
"FileName": "concatenate.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:09:58.29Z",
"UpdateTime": "2014-08-22T21:01:09.257Z",
"FileUpdateTime": "2014-08-22T21:01:09.257Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "8775",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "concatenate.oxygenicity",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
},
{
"instanceId": "100e8c87-9585-4d5f-8c25-e327f8e1d74e",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "DjBREV7zWcqXWaBYFLI+xKdbuc=",
"properties": {
"FileName": "furrily.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:10:42.697Z",
"UpdateTime": "2014-08-22T21:02:30.357Z",
"FileUpdateTime": "2014-08-22T21:02:30.357Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "526",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "furrily.supersensual",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
}
]
}
Usage example
$.get("https://localhost/ws/v2.5/Repositories/Bentley.PW--PW/PW_WSG/Document/?$filter=PW_WSG.DocumentParent-forward-PW_WSG.Project.$id+eq+'c78aa831-109d-4ad7-9307-fb651f682a4a'",
function(data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].id);
}
},
"json"
);
Retrieves a list of all instances in class1 related to the instance with an instanceId of class2. This is another form that retrieves the same results as using:
This shorter form is possible only when class “class1” and class “class2” have a single possible relationship defined in the schema.
Response example
{
"instances": [
{
"instanceId": "6b7d6991-82ae-4060-b1f3-d810d270e127",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "NLUKmsIl2eRij9C+fsGttWI51cA=",
"properties": {
"FileName": "concatenate.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:09:58.29Z",
"UpdateTime": "2014-08-22T21:01:09.257Z",
"FileUpdateTime": "2014-08-22T21:01:09.257Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "8775",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "concatenate.oxygenicity",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
},
{
"instanceId": "100e8c87-9585-4d5f-8c25-e327f8e1d74e",
"className": "Document",
"schemaName": "PW_WSG",
"eTag": "DjBREV7zWcqXWaBYFLI+xKdbu/c=",
"properties": {
"FileName": "furrily.json",
"MimeType": "unknown",
"CreateTime": "2014-08-22T20:10:42.697Z",
"UpdateTime": "2014-08-22T21:02:30.357Z",
"FileUpdateTime": "2014-08-22T21:02:30.357Z",
"CreatedById": 1,
"UpdatedById": 1,
"FileSize": "526",
"IsLatest": true,
"Description": "VisualStudioTests",
"Version": "",
"Name": "furrily.supersensual",
"IsLocked": false,
"ParentGuid": "3da143ea-23d5-4c6e-886d-4b1652ed4a18",
"FileUpdatedById": 1,
"EnvironmentId": 0
}
}
]
}
Usage example
$.get("https://localhost/ws/v2.5/Repositories/Bentley.PW--PW/PW_WSG/Project/c78aa831-109d-4ad7-9307-fb651f682a4a/PW_WSG.Document",
function(data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].id);
}
},
"json"
);
Since: 2.3
Retrieves a list of all instances in class1 related to the instance with an instanceId of class2 using a specified relationship. This is another form that retrieves the same results as using:
Please refer to GET v2.5/Repositories/{repositoryId}/{schema2}/{class2}/{instanceId}/{schema1}.{class1} for usage and response examples.
Creates a new instance with the posted property values under the optionally specified related instance. For file creation and content upload please refer to Persistence file service support
Since: 1.1
Parameters
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing the class. |
class |
Required. The class name of the object to create. |
Response example
{
"changedInstance":
{
"change":"Created",
"instanceAfterChange": {
"instanceId": "6de337b1-86b2-4b7e-b6f0-e7668dc0a8cb",
"className": "document",
"schemaName": "{schema}",
"properties": {
"name":"MyText.txt",
"version":"Testing",
"description":null
},
"relationshipInstances":[
{
"instanceId":"2acbffec-88f5-4216-bf8c-1a042cbb5f36",
"className":"DocumentParent",
"schemaName":"{schema}",
"direction":"forward",
"properties":{},
"relatedInstance": {
"instanceId":"8db0c801-cceb-4b18-8d50-75d542eed35a",
"className":"project",
"schemaName":"{schema}",
"properties":{}
}
}
]
}
}
}
Usage example
// The following C# example illustrates posting a document with file in one request.
private static string PostDocumentWithFileInOneRequest ()
{
var repository = "{RepositoryId}";
var schema = "{Schema}";
var schemaClass = "{Class}";
// set id empty to create new instance
var instanceId = "{InstanceId}";
var existingProjectId = "{ExistingProjectId}";
Uri requestUri = new Uri(String.Format("https://localhost/v2.5/Repositories/{0}/{1}/{2}/{3}", repository, schema, schemaClass, instanceId));
var filepath = "{FilePath}";
var fileName = new System.IO.FileInfo(filepath).Name;
// Creating json that describes document with property 'name'
JObject documentToPost = CreateClassInstance("Document", schema, null, new KeyValuePair<string, object>("name", fileName));
// Specifying relationship that binds document to its parent (project)
JObject relationship = CreateRelationshipClassInstance("DocumentParent", schema, null, "forward");
// specifying document parent that is existing project with its id
JObject documentParent = CreateClassInstance("Project", schema, existingProjectId);
JToken json = CreateJson(documentToPost, relationship, documentParent);
var jsonInstance = json.ToString();
// Posting document
using (var client = new HttpClient())
{
var multipartContent = new MultipartContent("form-data", "-----------------------------" + Guid.NewGuid().ToString("N"));
var stringContent = new StringContent(jsonInstance, null, "application/json");
multipartContent.Add(stringContent);
stringContent.Headers.Add("Content-Disposition", "form-data; name=\"instance\"");
var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(filepath));
fileContent.Headers.Add("Content-Disposition", String.Format("form-data; name=\"file\"; FileName=\"{0}\"", fileName));
multipartContent.Add(fileContent);
return client.PostAsync(requestUri, multipartContent).Result.Content.ReadAsStringAsync().Result;
}
}
private static JObject CreateClassInstance (string className, string schemaName, string id, params KeyValuePair<string, object>[] properties)
{
var newClass = new JObject ();
newClass.Add ("className", className);
newClass.Add ("schemaName", schemaName);
newClass.Add ("instanceId", id);
if (properties.Length > 0)
{
var propertiesObject = new JObject ();
foreach (KeyValuePair<string, object> property in properties)
{
propertiesObject.Add (property.Key, Newtonsoft.Json.JsonConvert.SerializeObject (property.Value));
}
newClass.Add ("properties", propertiesObject);
}
return newClass;
}
private static JObject CreateRelationshipClassInstance (string className, string schemaName, string id, string direction, params KeyValuePair<string, object>[] properties)
{
JObject relationshipClass = CreateClassInstance (className, schemaName, id, properties);
relationshipClass.Add ("direction", direction);
return relationshipClass;
}
private static JToken CreateJson (JObject instance, JObject relationshipInstance, JObject relatedInstance)
{
relationshipInstance.Add ("relatedInstance", relatedInstance);
var relationshipsArray = new JArray ();
relationshipsArray.Add (relationshipInstance);
instance.Add ("relationshipInstances", relationshipsArray);
var json = new JObject ();
json.Add ("instance", instance);
return json;
}
<!DOCTYPE html>
<html>
<head>
<title>Sample multipart post</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
function getCreateTabFile() {
return $('#fileInput')[0].files[0];
}
function getUploadUrl() {
return $('#url').val();
}
function getAuthHeader() {
return $('#authHeader').val();
}
function getInstanceJson() {
return $('#bodyInput').val();
}
function uploadFile(url, instanceBody, file, authHeader) {
var params = {
address: url,
body: instanceBody,
file: file,
};
var formData = new FormData();
formData.append('file', params.file, params.file.name);
formData.append('instance', new Blob([params.body], {
type: "application/json"
}));
$.support.cors = true; //for IE
$.ajaxSetup({
async: true,
type: 'POST',
url: params.address
});
var ajax = {};
ajax.beforeSend = function(xhr) {
xhr.setRequestHeader('Authorization', authHeader);
};
ajax.data = formData;
ajax.processData = false;
ajax.contentType = false;
return $.ajax(ajax);
}
$(document).ready(function () {
$('#uploadButton').on('click', function() {
var response = {};
uploadFile(getUploadUrl(), getInstanceJson(), getCreateTabFile(), getAuthHeader()).done(function(data, textStatus, jqXHR) {
response.success = true;
response.status = jqXHR.status;
response.statusText = jqXHR.statusText;
try {
response.data = JSON.parse(jqXHR.responseText);
} catch (exception) {
response.data = jqXHR.responseText;
}
alert(JSON.stringify(response));
}).fail(function(jqXHR, textStatus, err) {
response.success = (jqXHR.status < 400 && jqXHR.status > 0);
response.status = err.code || jqXHR.status;
response.statusText = jqXHR.statusText;
try {
response.responseText = JSON.parse(jqXHR.responseText).errorMessage;
} catch (exception) {}
try {
response.data = JSON.parse(jqXHR.responseText);
} catch (exception) {
response.data = jqXHR.responseText;
}
response.headers = jqXHR.getAllResponseHeaders();
alert(JSON.stringify(response));
});
});
});
</script>
</head>
<body>
<input id="fileInput" type="file" name="file" />
<br>
<input id="url" type="text" name="url" placeholder="{Host}/{WsgVersion}/Repositories/{RepositoryId}/{Schema}/{Class}/{InstanceId}" style="width:500px" />
<br>
<input id="authHeader" type="text" name="authHeader" placeholder="Auth header value." style="width:500px" />
<br>
<textarea id="bodyInput" type="textarea" name="bodyInput" rows="20" cols="80" placeholder="Instance json."></textarea>
<button id="uploadButton">Upload</button>
</body>
</html>
Updates existing instance properties in the repository and optionally uploads file content associated with the instance that replaces the existing file.
Since: 2.0
Parameters
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing the class. |
class |
Required. The class name of the instance to be updates. |
instanceId |
Required. The ID of the instance to be updated. |
The content can be posted in the following formats:
Updating an instance and file with resumable requests works the same way as described in PUT v2.5/Repositories/{repositoryId}/{schema}/{class}/{instanceId}/$file. The only difference is JSON body in the handshake request. If you use JavaScript, URL escape should be used for file name in headers as well as adding parameter "IsFileNameUrlEncoded" equal to true for Content-Disposition header.
Example:
Request headers:
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
Authorization: Basic YWRtaW46YWRtaW4=
Request body:
---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"
Content-Type: application/json
{
"instance" : {
"instanceId": "585da57b-667c-459e-8223-9930b7335bf0",
"className": "document",
"schemaName": "PW_WSG",
"properties": { "Name": "Document1.txt" },
"relationshipInstances": [{
"className": "DocumentParent",
"schemaName": "PW_WSG",
"direction": "forward",
"relatedInstance": {
"instanceId": "99faa16e-06cc-4c7f-9c0f-73aef604bc17",
"className": "Project",
"schemaName": "PW_WSG"
}
}]
}
}
---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"; filename="Test.txt"
Content-Type: text/plain
{File Content}
---------------------------acebdf13572468—
Response example
A response with status 200 (OK).
Deletes an existing object instance in the repository with the optionally posted property values.
Since: 2.0
Parameters
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing the class. |
class |
Required. The class name of the instance to be deleted. |
instanceId |
Required. The ID of the instance to be deleted. |
Response example
A response with status 200 (OK).
Usage example – empty delete request
$.ajax({
url: "https://localhost/ws/v2.5/Repositories/Bentley.PW--PW/PW_WSG/Project/6b7d6991-82ae-4060-b1f3-d810d270e127",
type: "DELETE",
});
Usage example – delete request with JSON body
$.ajax({
url: "https://localhost/ws/v2.5/Repositories/Bentley.PW--PW/PW_WSG/Project/6b7d6991-82ae-4060-b1f3-d810d270e127",
type: "DELETE",
data: "{ instance: {
instanceId: '6b7d6991-82ae-4060-b1f3-d810d270e127',
className: 'Project',
schemaName: 'PW_WSG'
properties:
{
Name: 'My new name'
},
}
}",
beforeSend : function(req) {
req.setRequestHeader('content-type', 'application/json');
}
});
Creates, updates, and deletes multiple instances in the same request. JSON must contain an instance graph (root instance and related instances) with change state information. Each instance should contain a changeState value explicitly specifying the action to be performed. Possible changeState values:
The request URL should match the root instance operation. For example, if the root instance is being modified, the URL must contain {instanceId}. The same {instanceId} must be skipped in the instance creation request.
Similarly for single instance requests, if the request URL implies an update or a new instance operation, then the changeState on the root instance is optional. If JSON contains an instance with an empty instance Id, the “new” operation is assumed automatically.
JSON example:
{
"instance": {
"instanceId": "123",
"className": "Company",
"schemaName": "Staff",
"changeState": "modified",
"properties": {
"Name": "Bentley"
},
"relationshipInstances": [
{
"instanceId": "relationship1",
"className": "Company_x_Employee",
"schemaName": "Staff",
"direction": "forward",
"changeState": "new",
"relatedInstance": {
"instanceId": "ned",
"className": "Employee",
"schemaName": "Staff",
"changeState": "new",
"properties": {
"Name": "Ned Flanders",
"Role": "Software Engineer"
}
}
}
]
}
}
Response example
{
"changedInstance": {
"change": "Modified",
"instanceAfterChange": {
"instanceId": "b97fe947-4bc5-4ef0-a06b-729759935782",
"className": "Document",
"schemaName": "PW_WSG",
"properties": {
"Name": "Name1",
"FileName": null,
"Description": null,
"MimeType": null,
"Version": null
},
"relationshipInstances": [
{
"instanceId": "b97fe947-4bc5-4ef0-a06b-729759935783",
"className": "DocumentParent",
"schemaName": "PW_WSG",
"direction": "forward",
"properties": {},
"relatedInstance": {
"instanceId": "ae12f364-3aac-4dee-81fc-90d646b6b81d",
"className": "Project",
"schemaName": "PW_WSG",
"properties": {
"Name": "Test1"
}
}
}
]
}
}
}
Web API batch supports the grouping of requests and sends them to the server as a single HTTP request. This functionality is based on standard Microsoft ASP.NET Web API 2 OData batch feature, allowing to pack several API requests and send them as a single request in the following procedures:
More information about batch requests can be found at https://blogs.msdn.com/b/webdev/archive/2013/11/01/introducing-batch-support-in-web-api-and-web-api-odata.aspx
Since: 2.0
Example of the request headers:
Content-Type: multipart/mixed; boundary=batch_dc3720cc-435b-4e7a-bcfd-44a569fe7240
Host: {wsg}
Example of the request body:
--batch_dc3720cc-435b-4e7a-bcfd-44a569fe7240
Content-Type: application/http; msgtype=request
POST /ws/v2.5/Repositories/{repositoryId}/{schema}/project/ HTTP/1.1
Host: {wsg}
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: application/json; charset=utf-8
{
"instance": {
"className": "project",
"schemaName": "{schema}",
"properties":{ "Name": "Name1" },
"relationshipInstances":[
{
"className": "projectParent",
"schemaName": "{schema}",
"direction": "forward",
"relatedInstance":{
"className": "project",
"schemaName": "{schema}",
"instanceId": "ae12f364-3aac-4dee-81fc-90d699b6b999"
}
}
]
}
}
--batch_dc3720cc-435b-4e7a-bcfd-44a569fe7240
Content-Type: application/http; msgtype=request
GET /ws/v2.5/Repositories/{repositoryId}/{schema}/project?$filter=name+eq+'Name2' HTTP/1.1
Host: {wsg}
Authorization: Basic YWRtaW46YWRtaW4=
--batch_dc3720cc-435b-4e7a-bcfd-44a569fe7240
Content-Type: application/http; msgtype=request
GET /ws/v2.5/Repositories/{repositoryId}/{schema}/project?$filter=name+like+'Name3' HTTP/1.1
Host: {wsg}
Authorization: Basic YWRtaW46YWRtaW4=
--batch_dc3720cc-435b-4e7a-bcfd-44a569fe7240--
Response example:
--969eb9a6-7129-481c-9f78-f20a699422a0
Content-Type: application/http; msgtype=response
HTTP/1.1 201 Created
Location: https://localhost/ws/ws/v2.5/Repositories/{repositoryId}/{schema}/project/ac9e7d75-9999-499a-b136-2ff79f211fbc
Content-Type: application/json; charset=utf-8
{
"changedInstance": {
"change": "Created",
"instanceAfterChange": {
"instanceId": "ac9e7d75-9999-499a-b136-2ff79f211fbc",
"className": "project",
"schemaName": "{schema}",
"properties": {
"Name1": "12345677",
"description": null
},
"relationshipInstances": [{
"instanceId": "8054b041-2f35-434d-aef0-0babbd288f2f",
"className": "ProjectParent",
"schemaName": "{schema}",
"direction": "forward",
"properties": {},
"relatedInstance": {
"instanceId": "ae12f364-3aac-4dee-81fc-90d646b6b81d",
"className": "project",
"schemaName": "{schema}",
"properties": {}
}
}]
}
}
}
--969eb9a6-7129-481c-9f78-f20a699422a0
Content-Type: application/http; msgtype=response
HTTP/1.1 200 OK
ETag: "2jmj7l5rSw0yVb/vlWAYkK/YBwk="
Content-Type: application/json; charset=utf-8
{"instances":[]}
--969eb9a6-7129-481c-9f78-f20a699422a0
Content-Type: application/http; msgtype=response
HTTP/1.1 200 OK
ETag: "2jmj7l5rSw0yVb/vlWAYkK/YBwk="
Content-Type: application/json; charset=utf-8
{"instances":[]}
--969eb9a6-7129-481c-9f78-f20a699422a0—
Usage example
Please note: System.Net.Http.Formatting reference is needed (add it by installing Nugent via package manager console "Install-Package System.Net.Http.Formatting.Extension").
public void Batch()
{
string url = "https://localhost/ws/v2.5/Repositories/";
string batchUrl = "https://localhost/ws/v2.5/$batch";
MultipartContent contents = new MultipartContent ("mixed", "batch_dc3720cc-435b-4e7a-bcfd-44a569fe7240")
{
new HttpMessageContent (new HttpRequestMessage ( HttpMethod.Post, url + "{repositoryId}/{schema}/project/")
{
Content = new StringContent (@"{""instance"":{""properties"":{""name"":""Name1""},""relationshipInstances"":[{""relatedInstance"":{""className"":""project"",""schemaName"":""{schema}"",""instanceId"":""ae12f364-3aac-4dee-81fc-90d646b6b81d""},""className"":""projectParent"",""schemaName"":""{schema}"", ""direction"":""forward""}],""className"":""project"",""schemaName"":""{schema}""}}", Encoding.UTF8, "application/json")
}),
new HttpMessageContent (new HttpRequestMessage( HttpMethod.Get, url + "{repositoryId}/{schema}/project/?filter=name+eq+'Name2'")),
new HttpMessageContent (new HttpRequestMessage( HttpMethod.Get, url + "{repositoryId}/{schema}/project/?filter=name+like+'Name3'"))
};
foreach (var content in contents)
{
((HttpMessageContent)content).HttpRequestMessage.Headers. Authorization = new AuthenticationHeaderValue ("basic", "YWRtaW46YWRtaW4=");
}
HttpClient client = new HttpClient ();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("basic", "YWRtaW46YWRtaW4=");
HttpResponseMessage response = client.PostAsync (batchUrl, contents).Result;
MultipartStreamProvider streamProvider = response.Content.ReadAsMultipartAsync ().Result;
foreach (HttpContent content in streamProvider.Contents)
{
//Do something
}
}
Web API changeSet supports sending multiple instance changes as a single request. This supports:
Note: Changeset does not currently accept mime/multipart requests.
Each instance should contain a changeState value that explicitly specifies the action to be performed. Refer to POST v2.5/{globalSchema}/{globalInstanceId}/{schema}/{class}/{instanceId} (for multiple instances) for more information on how to make a valid single instance JSON.
Example of the request body:
{
"instances": [{
"className": "Project",
"schemaName": "PW_WSG",
"changeState": "new",
"properties": {
"Name": "MSA_fold_new"
},
"relationshipInstances": [{
"className": "ProjectParent",
"schemaName": "PW_WSG",
"direction": "forward",
"relatedInstance": {
"instanceId": "ba352e35-4a85-4092-b7ee-436d0aa3cfca",
"className": "Project",
"schemaName": "PW_WSG"
}
}]
},{
"className": "Document",
"schemaName": "PW_WSG",
"changeState": "modified",
"instanceId": "0e02f061-4b3e-4584-b8fa-b4ea34865b5d",
"properties": {
"Name": "file_modified"
},
"relationshipInstances": [{
"className": "DocumentParent",
"schemaName": "PW_WSG",
"direction": "forward",
"relatedInstance": {
"instanceId": "ba352e35-4a85-4092-b7ee-436d0aa3cfca",
"className": "Project",
"schemaName": "PW_WSG"
}
}]
},{
"className": "Project",
"schemaName": "PW_WSG",
"changeState": "deleted",
"instanceId": "ea20c8c2-d923-4311-ba36-0af77debeea8"
}]
}
Response example:
{
"changedInstances":[{
"change":"Created",
"instanceAfterChange": {
"instanceId":"18da79f0-19cd-41c6-b822-3908e7681591",
"schemaName":"PW_WSG",
"className":"Project",
"properties": {
"Name":"MSA_fold_new",
"Description":null,
"EnvironmentId":null,
"IsRichProject":null,
"WorkflowId":null
},
"relationshipInstances": [{
"instanceId":"",
"schemaName":"PW_WSG",
"className":"ProjectParent",
"direction":"forward",
"properties":{},
"relatedInstance": {
"instanceId":"ba352e35-4a85-4092-b7ee-436d0aa3cfca",
"schemaName":"PW_WSG",
"className":"Project",
"properties": {
"Name":null,
"Description":null,
"EnvironmentId":null,
"WorkflowId":null
}
}
}]
}
},{
"change":"Modified",
"instanceAfterChange": {
"instanceId":"0e02f061-4b3e-4584-b8fa-b4ea34865b5d",
"schemaName":"PW_WSG",
"className":"Document",
"properties": {
"Name":"file_modified",
"FileName":null,
"Description":null,
"MimeType":null,
"Version":null,
"StateId":null,
"IsFinal":null
},
"relationshipInstances": [{
"instanceId":"",
"schemaName":"PW_WSG",
"className":"DocumentParent",
"direction":"forward",
"properties":{},
"relatedInstance": {
"instanceId":"ba352e35-4a85-4092-b7ee-436d0aa3cfca",
"schemaName":"PW_WSG",
"className":"Project",
"properties": {
"Name":null,
"Description":null,
"EnvironmentId":null,
"WorkflowId":null
}
}
}]
}
},{
"change":"Deleted",
"instanceAfterChange": {
"instanceId":"ea20c8c2-d923-4311-ba36-0af77debeea8",
"schemaName":"PW_WSG",
"className":"Project",
"properties": {
"Name":null
}
}
}]
}
Downloads a file associated with the specified instance.
Recommended file download workflow:
File download workflow with an option to resume a broken download in the event that the connection is lost:
Since: 1.1
Parameters
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing the class. |
class |
Required. The class name of the instance with associated file. |
instanceId |
Required. The ID of the instance for which to get the file. |
Response example:
Response is the file being downloaded.
Usage example:
window.open("https://localhost/ws/v2.5/Repositories/{RepositoryId}/{Schema}/document/{DocumentId}/$file");
Uploads a file content associated with the instance, replacing the existing file, if any.
File can be uploaded as byte/stream content in one request without any additional HTTP headers. Otherwise, it is possible to upload files in parts with a possibility to resume upload in the event of a lost connection. The multipart file upload workflow:
Since: 1.1
Parameters
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing the class. |
class |
Required. The class name of the instance for which to update the file. |
instanceId |
Required. The ID of the instance for which to update the file. |
Example of uploading an entire file with one request:
Headers:
Content-Type: text/plain
Content-Length: {length}
Content-Disposition: attachment; filename="FileName.txt"
Authorization: Basic YWRtaW46YWRtaW4=
Body:
<Text file contents…>
Response:
Headers:
HTTP/1.1 200 OK
Content-Length: 224
Content-Type: application/json; charset=utf-8
ETag: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Server: Bentley-WSG/02.00.05.13
Server: Bentley-WebAPI/2.4
Date: Thu, 26 Jun 2014 08:26:18 GMT
Body:
{
"changedInstance": {
"change": "Modified",
"instanceAfterChange": {
"instanceId": "172c4b1d-0551-495b-b2ed-6ff79d1ab120",
"className": "document",
"schemaName": "{schema}",
"properties": {
"name": null,
"filename": null,
"description": null
}
}
}
}
Example of uploading a file divided into parts:
Request 1 - 'handshake':
Headers:
Authorization: Basic YWRtaW46YWRtaW4=
Content-Disposition: attachment; filename="FileName.txt"
Content-Range: bytes */30
Content-Length: 0
Body:
<EMPTY>
Response to the request 1:
HTTP/1.1 308
Content-Length: 0
ETag: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Server: Bentley-WSG/02.00.05.13
Server: Bentley-WebAPI/2.4
Date: Thu, 26 Jun 2014 06:58:17 GMT
Request 2 - sending first 15 bytes:
Headers:
Content-Type: text/plain
Authorization: Basic YWRtaW46YWRtaW4=
If-Match: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Content-Range: bytes 0-14/30
Content-Length: 15
Body:
<First 15 bytes of file>
Response to the request 2:
HTTP/1.1 308
Content-Length: 0
ETag: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Server: Bentley-WSG/02.00.05.13
Server: Bentley-WebAPI/2.4
Range: bytes=0-14
Date: Thu, 26 Jun 2014 07:03:51 GMT
Request 3 - send last part of file
Headers:
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: text/plain
If-Match: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Content-Range: bytes 15-29/30
Content-Length: 15
Body:
<Last 15 bytes of file>
Response to the request 3:
Headers:
HTTP/1.1 200 OK
Content-Length: 224
Content-Type: application/json; charset=utf-8
ETag: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Server: Bentley-WSG/02.00.05.13
Server: Bentley-WebAPI/2.4
Date: Thu, 26 Jun 2014 08:26:18 GMT
Body:
{
"instanceId": "172c4b1d-0551-495b-b2ed-6ff79d1ab120",
"className": "document",
"schemaName": "{schema}",
"properties": {
"name": null,
"filename": null,
"description": null
}
}
Usage example
// The following C# example illustrates uploading a file in multiple parts.
var guid = "b65018d6-3630-4566-958c-3934e4055c42";
Uri request = new Uri(String.Format("https://localhost/ws/v2.5/Repositories/pw--PW/document/{0}/$file", guid));
Stream uploadFile = new MemoryStream(Encoding.UTF8.GetBytes("My file2 contents...."));
string fileName = "MyFileName.txt";
using (var file = uploadFile)
{
HttpResponseMessage response;
do
{
using (var client = new HttpClient())
{
var credentials = "admin:admin";
credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
client.DefaultRequestHeaders.Add("Authorization", String.Format("Basic {0}", credentials));
// 1. Send an initial "handshake" request to inform the server of the total
// size of the file that will be uploaded;
HttpContent content = new StringContent("");
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
content.Headers.ContentDisposition.FileName = fileName;
content.Headers.Add("Content-Range", String.Format("bytes */{0}", file.Length));
response = client.PutAsync(request, content).Result;
if (response.StatusCode != (HttpStatusCode)308)
{
break; // Either Created or an error, handle outside loop.
}
int bufferSize = 1024 * 1024; // 1 MB
var buffer = new byte[bufferSize];
// 2. Send the file:
// When the server is still missing some bytes the response will have a status of 308 (Resume Incomplete):
while (response.StatusCode == (HttpStatusCode)308)
{
// Response header Range: bytes=0-{endByteIndex} indicates how many bytes the server has received and saved.
long start = 0;
if (response.Headers.Contains("Range")) // No Range header indicates that the server has 0 bytes of the file.
{
string range = response.Headers.GetValues("Range").First();
RangeHeaderValue parsedValue = RangeHeaderValue.Parse(range);
start = (long)parsedValue.Ranges.First().To + 1;
}
file.Position = start;
int readCount = file.Read(buffer, 0, bufferSize);
// Send a request with the file content and Content-Range: bytes {startByteIndex}-{endByteIndex}/{fileSize} header:
content = new ByteArrayContent(buffer, 0, readCount);
content.Headers.ContentRange = new ContentRangeHeaderValue(start, start + readCount - 1, file.Length);
// A successful response will have an ETag header by which the upload is identified:
client.DefaultRequestHeaders.IfMatch.Clear();
client.DefaultRequestHeaders.IfMatch.Add(response.Headers.ETag);
response = client.PutAsync(request, content).Result;
}
}
} while (response.StatusCode == HttpStatusCode.PreconditionFailed); // If If-Match did not match restart the upload process.
// 3. Handle the final response:
if (response.StatusCode != HttpStatusCode.OK)
{
// Error handling should be implemented here.
return "error";
}
else
{
string createdObjectIdJson = response.Content.ReadAsStringAsync().Result;
}
}
Creates a new file instance with the posted property values under the optionally specified related instance. File create and content can be performed in the following formats:
File creation and content upload using "Multipart/form-data". Example:
POST https://localhost/ws/v2.5/Repositories/{repositoryId}/{schema}/{fileClass}
Headers:
Authorization:Basic YWRtaW46YWRtaW4=
Content-Type:multipart/form-data; boundary=-------------------------acebdf13572468
Body:
---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"
Content-Type: application/json
{
"instance": {
"schemaName": "{schema}",
"className": "File",
"changeState": "new",
"properties": { "Name": "Test.txt" },
"relationshipInstances" : [{
"className" : "DocumentFiles",
"schemaName" : "{schema}",
"direction" : "backward",
"properties" : {},
"relatedInstance" : {
"instanceId" : "{instanceId}",
"className" : "Global_Document_DOC1",
"schemaName" : "{schema}",
}
}]
}
}
---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"; filename="Test.txt"
Content-Type: text/plain
"file content text"
---------------------------acebdf13572468--
Response:
{
"changedInstance": {
"change":"Created",
"instanceAfterChange": {
"instanceId":"{instanceId}",
"schemaName":"{schema}",
"className":"File",
"properties": { "Name":"Test_12.txt" },
"relationshipInstances": [{
"instanceId":"{instanceId}",
"schemaName":"{schema}",
"className":"DocumentFiles",
"direction":"backward",
"properties":{},
"relatedInstance": {
"instanceId":"{instanceId}",
"schemaName":"{schema}",
"className":"Global_Document_DOC1",
"properties":{}
}
}]
}
}
}
File creation and content upload using "resumable file upload". Example:
Request 1 - 'handshake' with JSON body:
POST https://localhost/ws/v2.5/Repositories/{repositoryId}/{schema}/{fileClass}
Headers:
Content-Range: bytes */36
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: application/json
Content-Disposition: attachment; filename="test3.txt"
Content-Length: 0
Body:
{
"instance" : {
"className": "File",
"schemaName": "{schema}",
"properties": { "Name": "test3.txt" },
"relationshipInstances": [{
"className": "DocumentFiles",
"schemaName": "{schema}",
"direction": "backward",
"relatedInstance": {
"instanceId": "{instanceId}",
"className": "{documentClass}",
"schemaName": "{schema}"
}
}]
}
}
Response to the request 1:
HTTP/1.1 308
Content-Length: 0
ETag: "1+36+rs0KaklyqidA7raqntvBzusuBnc="
Server: Bentley-WSG/02.00.05.13
Server: Bentley-WebAPI/2.4
Date: Wed, 12 Oct 2016 11:05:04 GMT
Request 2 - sending first 21 bytes:
POST https://localhost/ws/v2.5/Repositories/{repositoryId}/{schema}/{fileClass}
Headers:
Content-Type: text/plain
Authorization: Basic YWRtaW46YWRtaW4=
If-Match: "1+36+rs0KaklyqidA7raqntvBzusuBnc="
Content-Range: bytes 0-20/36
Content-Length: 21
Body:
<First 21 bytes of file>
Response to the request 2:
HTTP/1.1 308
Content-Length: 0
ETag: "1+36+rs0KaklyqidA7raqntvBzusuBnc="
Range: bytes=0-20
Server: Bentley-WSG/02.00.05.13
Server: Bentley-WebAPI/2.4
Date: Wed, 12 Oct 2016 11:06:07 GMT
Request 3 - send last part of file
POST https://localhost/ws/v2.5/Repositories/{repositoryId}/{schema}/{fileClass}
Headers:
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: text/plain
If-Match: "1+36+rs0KaklyqidA7raqntvBzusuBnc="
Content-Range: bytes 21-35/36
Content-Length: 15
Body:
<Last 15 bytes of file>
Response to the request 3:
Headers:
HTTP/1.1 201 OK
Content-Length: 224
Content-Type: application/json
ETag: "1+36+rs0KaklyqidA7raqntvBzusuBnc="
Server: Bentley-WSG/02.00.05.13
Server: Bentley-WebAPI/2.4
Date: Wed, 12 Oct 2016 11:06:31 GMT
Body:
{
"instanceId": "{instanceId}",
"className": "file",
"schemaName": "{schema}",
"properties": {
"name": "{value}",
},
"relationshipInstances": [{
"className": "DocumentFiles",
"schemaName": "{schema}",
"direction": "backward",
"properties": {},
"relatedInstance": {
"instanceId": "{instanceId}",
"className": "DocumentFiles",
"schemaName": "{schema}",
"properties": {}
}
}]
}
Allows to update instance properties and uploads a file content associated with the instance.
The workflow is almost identical to "PUT" case with minor differences:
Example of updating instance and uploading a file divided into parts:
Request 1 - 'handshake' + properties update:
POST https://localhost/ws/v2.5/Repositories/{repositoryId}/{schema}/{fileClass}/{instanceId}
Headers:
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: application/json
Content-Disposition: attachment; filename="FileName.txt"
Content-Range: bytes */30
Content-Length: 151
Body:
{
"instance": {
"instanceid": "{fileInstanceId}",
"className": "file",
"schemaName": "{schema}",
"properties": { "isCheckedOut": false }
}
}
Response to the request 1:
HTTP/1.1 308
Content-Length: 0
ETag: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Server: Bentley-WSG/02.00.05.10
Server: Bentley-WebAPI/2.4
Date: Wed, 05 Oct 2016 15:11:20 GMT
Request 2 - sending first 15 bytes:
POST https://localhost/ws/v2.5/Repositories/{repositoryId}/{schema}/{fileClass}/{instanceId}
Headers:
Content-Type: text/plain
Authorization: Basic YWRtaW46YWRtaW4=
If-Match: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Content-Range: bytes 0-14/30
Content-Length: 15
Body:
<First 15 bytes of file>
Response to the request 2:
HTTP/1.1 308
Content-Length: 0
ETag: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Server: Bentley-WSG/02.00.05.10
Server: Bentley-WebAPI/2.4
Range: bytes=0-14
Date: Wed, 05 Oct 2016 15:11:20 GMT
Request 3 - send last part of file
POST https://localhost/ws/v2.5/Repositories/{repositoryId}/{schema}/{fileClass}/{instanceId}
Headers:
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: text/plain
If-Match: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Content-Range: bytes 15-29/30
Content-Length: 15
Body:
<Last 15 bytes of file>
Response to the request 3:
Headers:
HTTP/1.1 200 OK
Content-Length: 224
Content-Type: application/json; charset=utf-8
ETag: "0+30+72ia7FC3WFHxKWeDx2Vzxg=="
Server: Bentley-WSG/02.00.05.10
Server: Bentley-WebAPI/2.4
Date: Wed, 05 Oct 2016 15:11:20 GMT
Body:
{
"changedInstance":{
"change":"Modified",
"instanceAfterChange":{
"instanceId":"1825",
"schemaName":"{schema}",
"className":"File",
"properties":{
"IsCheckedOut":false,
"Name":"FileName.txt",
"Path":"{path}",
"FileDate":"2016-09-21T18:28:24",
"FileSize":"24",
"PageSize":"",
"Id": 1824,
"IsHistoric":false,
"IsLocked":false,
"Remarks":"",
"IsPending":false,
"DateAdded":"2016-10-05T13:46:01.583",
"DateChanged":"2016-10-05T18:12:43.777",
"InDefaultScope":true,
"InDefaultVisibleScope":true,
"ScopeName":"Global",
"ScopeId":1,
"MimeType":"TEXT/PLAIN"
}
}
}
}
Since: 2.8
Additional 4-number product version value of a particular plugin can be appended to standard Server and custom Mas-Server headers if needed.
There are few conditions to meet:
GET https://localhost/ws/v2.8/Repositories/Bentley.YourPlugin--YourLocation/MetaSchema/ECSchemaDef/
Example 1:
Assuming there is a repository with a backing persistence provider:
GET https://localhost/ws/v2.8/Repositories/Bentley.YourPlugin--YourLocation/MetaSchema/ECSchemaDef/
Request headers:
Authorization: Basic YWRtaW46YWRtaW4=
Response example:
HTTP/1.1 200 OK
Cache-Control: must-revalidate, no-cache, private
Pragma: no-cache
Content-Length: {contentLength}
Content-Type: application/json
ETag: "{eTagValue}"
Server: mas-server:Bentley-WSG/02.06.06.06, Bentley-WebAPI/2.7, Bentley.YourPlugin/01.00.00.00
Mas-Server: mas-server:Bentley-WSG/02.06.06.06, Bentley-WebAPI/2.7, Bentley.YourPlugin/01.00.00.00
Mas-Request-Id: {RequestId}
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Date: {dateTime}
...
This section contains detailed information about instance querying options. As Bentley Web Service Gateway Web API exposes all information as instances, the same query options are available for all GET requests. Each repository might choose to support only a part of the options.
Web API supports queries for instances of multiple classes in the same request.
When querying for the multiple classes, query options $filter and $select can contain only the properties that can be specified without mentioning the class name (for example, when querying for Folder and Document, property Name can be used, but not Folder.Name nor Document.Name). Please refer to the OData style query string specification for a full OData query description and examples.
Query for instances of specified classes from the same schema.
Since: 2.0
Parameters
repositoryId |
Required. The ID of the repository against which to authenticate. |
schema |
Required. The name of the schema containing the class. |
classes |
Required. One or more comma separated class names. |
Example:
GET v2.5/Repositories/{repositoryId}/{schema}/Folder,Document?$select=Name
Query for multiple instances of specified classes that are related to the instance specified by {relatedClassSpec} and {relatedInstanceId}. Please refer to Relationships and related classes for more information about specifying related classes.
A search class name can be suffixed with the '!poly' keyword to indicate that a query should be executed as polymorphic. By default, all queries are non-polymorphic. The example query below will be executed for instances of classes Document, Asset and all classes derived from Asset, like Chair, Furniture, PC, etc.
GET v2.5/Repositories/{repositoryId}/{schema}/Asset!poly,Document
A class name can be prefixed with a schema name to indicate that the class is from a different schema than the default. If a class name is not prefixed with a schema name, the default schema specified in the URL (preceding the search classes’ specification) is used to find the class. The example query below will be executed for the instances of ClassA from main schema (SchemaA) and ClassB from a different schema (SchemaB).
GET v2.5/Repositories/{repositoryId}/SchemaA/ClassA,SchemaB.ClassB
The same prefix can also be applied before the class name in query options. The example query below will filter and select names of related Projects that are defined in a different schema.
For all instance requests, the query can be specified in an OData URL query format as URL query string parameters/options. Supported options:
{value} must be in one of these formats:
{value} must be of the same type as the property on the left side of expression.
To filter by instance IDs, {expr} can be $id in [‘ab’,’bc’] or $id+eq+'ab'.
To select all properties, specify $select=* or do not specify $select at all.
To select none of the properties, specify $select=$id
Example:
GET {schema}/{class1},{class2}/$count?$filter={filter}
Response:
{
"instances": [
{
"instanceId": "{instanceId}",
"schemaName": "{schema}",
"className": "InstanceCount",
"properties": {
"ECSchemaName": "{schema}",
"ECClassName": "{class1}",
"Count": 599
},
"eTag": "U99S1g99huTQSE8u2999999999s="
},
{
"instanceId": "{instanceId}",
"schemaName": "{schema}",
"className": "InstanceCount",
"properties": {
"ECSchemaName": "{schema}",
"ECClassName": "{class2}",
"Count": 120
},
"eTag": "UssS1g99aaaaSE8u2999999999s="
}
]
}
Example:
Note: for single instance GET requests, only the $select option is applicable.
Example:
GET v2.5/Repositories/{repositoryId}/{schema}/Document/123?$select=Name,Size,Description
Any query parameters/options unrecognized by Web Services Gateway Web API parser are treated as custom parameters and transferred to the plugin in the extended data of an ECQuery object. Custom parameters are plugin-specific and are not explained within the scope of this document.
Since: 2.0
Instructs plugin to query only instances directly or indirectly related to specified ancestor (for example – query all subdocuments under a specific folder, including all subfolders). Applied only if query contains at least one standard parameter.
Example: api.ancestor=List-ALU_Site~2F~7B4C836156-F690-4D6B-B9A0-0BF012270696~7D
Supported options: dash separated class name and instance ID
Since: 2.3
Specifies additional options for the plugin to use while filtering instances requested. CaseInsensitive option forces plugin to ignore case of the search text. If option is not specified, plugin can choose the default mode of operation.
Example: api.filtersettings=CaseInsensitive
Supported options: CaseInsensitive
Since: 2.4
Instructs plugin to return only one available FileAccess URL for each instance. AzulreBlobSasUrl URL type has higher priority than Default URL type.
Example: ../FileAccess/FileAccessKey?$filter=Permissions+eq+'Read'+and+{SchemaName}.{ClassName}.$id+eq+'{instanceId}'&api.singleurlperinstance=true
Supported options: true and false
Since: 2.2
Specifies additional options for the plugin to use while selecting instances requested.
Single option usage example: .../{schema}/{class}?$select={property1},{property2}&api.selectsettings=DistinctValues
Multiple options usage example: .../{schema}/{class}?$select={property1},{property2}&api.selectsettings=IncludeRelationshipsNotInSelect|DistinctValues|IncludeUnsetProperties
Supported options:
IncludeRelationshipsNotInSelectSince: 2.2 This setting instructs not to filter and return all relationships that are found by plugin (for example not only top level, but all tree of relationships). Example: .../{schema}/{class}?$select={property1},{property2}&api.selectsettings=IncludeUnrequestedRelationships |
DistinctValuesSince: 2.5 DistinctValues option instructs plugin to group instances by common property, provided in select option, values. DistinctValues is applied only if query contains select option with at least one property specified. Example: .../{schema}/{class}?$select={property1},{property2}&api.selectsettings=DistinctValues |
IncludeUnsetPropertiesSince: 2.6 IncludeUnsetProperties option allows to display properties without values within instances in queries. Example: .../{schema}/{class}?$select={property1},{property2}&api.selectsettings=IncludeUnsetProperties For a better explanation, let us have 1 instance:
The example query without 'IncludeUnsetProperties'. Request: GET v2.6/Repositories/{repositoryId}/{schema}/Fruit Response: Returns fruit instance with name and amount properties. Since, this apple instance has its color unset, color property is not being displayed.
The example query with 'IncludeUnsetProperties'. Request: GET v2.6/Repositories/{repositoryId}/{schema}/Fruit?api.selectsettings=IncludeUnsetProperties Response: Returns fruit instance with all properties. Although, color property is unset, it is still being displayed.
Another example of query with 'IncludeUnsetProperties', selecting only name and color properties. Request: Response: Returns fruit instance with two properties. Color property is unset, though it is still being displayed.
It is worth mentioning that there is a difference between instance having its property value unset and having value set to null. For example, we now have an instance with color property set as null:
Request: GET v2.6/Repositories/{repositoryId}/{schema}/Fruit Response: Returns fruit instance with all properties, since this 'Apple' instance has its color set (null).
|
Parameter aliases are parts of URL parameters that can be reused within a URL multiple times. When using complex query string, aliases usage helps to decrease length off the request URL and improve readability. By default, OData only specifies alias use in $filter and $orderby, while Bentley Web Services Gateway Web API supports aliases in multiple options. Aliases can be used to replace:
Alias syntax:
Examples:
GET v2.5/Repositories/{repositoryId}/{schema}/Employee?$orderby=@x&@x=Name
This section defines the syntax for related class specification the URL query string.
A property name in $filter and $select clauses can be prefixed with “relatedClassName.” to indicate that the property is from a class related to search classes. The example query retrieves documents with names of related projects.
GET v2.5/Repositories/{repositoryId}/{schema}/Document?$select=Project.Name
The query will return all instances without properties of the Document class and related instances with property Name of the class Project.
If there are multiple relationships between search classes and the related class, the relationship class name and direction must be specified by prefixing the property name with “relationshipClassName-direction-relatedClassName”. Direction can be the keywords “forward” or “backward.” The example query retrieves documents owned by user 'John'.
Related class specifications can be nested by using “/” as a delimiting character. The example query retrieves documents owned by users working at a company with the name Bentley.
In order to select all the properties of a related class, specify “relatedClassName.*” in the $select query option.
To select none of the properties of a related class, specify “relatedClassName.$id” in the $select query option.
Examples:
GET v2.5/Repositories/{repositoryId}/{schema}/Document?$select=Project.*,DocumentOwners-forward-User.$id
If $filter is not used, all Document instances will be returned without any properties (only instance IDs for all Document instances will be returned). Additionally, IDs of related instances of User class and all properties of related instances of Project class will be returned.
To select all properties of the root class and all properties of related class, it is possible to specify “*” in the $select value for both root and related classes:
GET v2.5/Repositories/{repositoryId}/{schema}/Document?$select=*,DocumentOwners-forward-User.*
To select all properties of root class and some of the properties of related class, separate properties by commas:
Since: 2.6
Filtering by multiple related properties for a single instance is supported.
$filter clause can contain a relationship specifier followed by parentheses containing multiple related property specifiers.
Example filter:
$filter=relationshipClassName-direction-relatedClassName(relatedProperty1 eq value and relatedProperty2 eq value2)
Relationship specifier
Relationship specifier format can be:
Relationship contents
Parentheses put after relationship specifier in filter clause may contain any filter that would be used for a related class defined in the specifier.
Example 1
We have 2 FruitBasket instances with some related fruits:
The example query retrieves FruitBaskets that have a related Fruit instance named 'Apple' with amount of 1.
Request:
Response:
Returns only instance 1 because it has matching Fruit instance.
{
"instances": [
{
"instanceId": "1",
"schemaName": "{schema}",
"className": "FruitBasket",
"properties": {},
"relationshipInstances":[
{
"instanceId":"2b2cc606-4c7c-4dd5-bbd9-9a082064c5fe",
"schemaName":"{schema}",
"className":"FruitsInBasket",
"direction":"forward",
"properties":{},
"relatedInstance": {
"instanceId":"3",
"schemaName":"{schema}",
"className":"Fruit",
"properties":{
"Name": "Apple",
"Amount": "1"
},
"eTag": ""lToc29LK7O0wLcqeJtICxjcoby7=""
},
"eTag": ""NQKxfbM8Hz1FDuHB/xILXDFp6U4=""
}
],
"eTag": ""UOxE31igPz6rHfYnut/z4xMj8bg=""
}
]
}
More supproted request examples:
GET v2.6-beta/Repositories/{repositoryId}/{schema}/FruitBasket?$filter=Fruit/Seed(Size+eq+'small')
GET v2.6-beta/Repositories/{repositoryId}/{schema}/FruitBasket?$filter=Fruit(Seed.Size+eq+'small')
GET v2.6-beta/Repositories/{repositoryId}/{schema}/FruitBasket?$filter=Fruit(Seed(Size+eq+'small'))
Result:
All of these requests will return instance 2, because it has a matching related instances.
Bentley Web Services Gateway Web API provides support for a Skip/Continuation token (commonly used in Cloud services) when the server operation can only run for a limited amount of time. In such workflows, the client receives a token to be used in subsequent calls to continue server processing from the last known position. Web API allows the exchange of tokens between plugin and client. If supported by the repository, the client will receive a token for SkipToken header in the response. For further request execution, send the token value in the SkipToken request header in subsequent requests.
Policies service exposes information about permissions and supported functionality in currently-running plugins and repositories.
Exposed schemas: Policies.
Exposed classes: PolicyAssertion.
Policies can be retrieved at different levels of granularity:
There are few Policy service types indicating an area of the policy:
These policies make sense only per plugin and repository levels.
Getting policy assertions for Persistence ServiceType by the Plugin/Repository/RepositoryConnection level will return Supported=true if any of the classes/instances supports the functionality in that Plugin/Repository/RepositoryConnection.
In addition to policies mentioned above, Persistence service type contains additional policies exposed from the plugin, but are not currently used by Web API:
It is worth mentioning that if policies like SortableQueries, SupportsMaxResults or SupportsResultRangeOffset are not supported, the functionality can still work. For example, if it is not supported by the ProjectWise plugin, then ECServices tries to apply its functionality to the results. (Example 1)
Example 1
By default, the SortableQueries policy for ProjectWise is not supported, but queries are still executable with the '$orderby' parameter to get sorted results:
Request:
GET v2.5/Repositories/{repositoryId}/policies/PolicyAssertion/Persistence.SortableQueries
Response:
{
"instances": [{
"instanceId": "Persistence.SortableQueries",
"schemaName": "Policies",
"className": "PolicyAssertion",
"properties": {
"ServiceType": "Persistence",
"Name": "SortableQueries",
"Supported": false,
"AdhocProperties": []
},
"eTag": ""pFj3hQuh+WgQ9czeYYoS08hd0Ks=""
}]
}
We can see that the “SortableQueries” policy is not supported. Now try to use “$orderby” parameter by querying documents.
Request:
Response:
{
"instances": [{
"instanceId": "4b270cd7-1e2a-4bb2-a0fa-468c02d5b517",
"schemaName": "PW_WSG",
"className": "Document",
"properties": {
"FileUpdateTime": "2013-01-07T12:25:23.61Z"
},
"eTag": ""12ShH/C/I2IPkeNRv9p+JbhmMes=""
},{
"instanceId": "51605460-2c65-44ac-b3f2-bd0dda3983ec",
"schemaName": "PW_WSG",
"className": "Document",
"properties": {
"FileUpdateTime": "2013-01-07T12:25:26.703Z"
},
"eTag": ""F8vdUB6hR9w3DL9JL6x5oDZNYd4=""
},{
"instanceId": "6cd7ed77-8f44-4db6-9313-6144edd2a9bf",
"schemaName": "PW_WSG",
"className": "Document",
"properties": {
"FileUpdateTime": "2013-02-13T12:55:32.887Z"
},
"eTag": ""YLtc+/cuLPAzExRi6vuzugfdKpg=""
}]
}
Example 2
Query for a repository connection service policy assertion named "Hidden" for the specified plugin.
This request maps to the RepositoryConnectionService.GetProviderPolicy method call.
Request:
Response:
{
"instances": [{
"instanceId": "RepositoryConnection.Hidden--Plugins.PluginIdentifier. Bentley.PW ",
"className": "PolicyAssertion",
"schemaName": "Policies",
"eTag": "lGoMJecbNcY6MX375uLGCoKgrJY=",
"properties": {
"Supported": false,
"ServiceType": "RepositoryConnection",
"Name": "Hidden"
}
}]
}
Example 3
Query for all policy assertions for a specified repository.
This request maps to the ECService.GetRepositoryPolicy method call.
Request:
Response:
{
"instances": [{
"instanceId": "RepositoryConnection.Openable--Repositories.RepositoryIdentifier. Bentley.PW--RepoServerName~3ARepoName",
"className": "PolicyAssertion",
"schemaName": "Policies",
"eTag": "IpBqrMF7lclul+/3CW5T+YcyTKw=",
"properties": {
"Supported": true,
"ServiceType": "RepositoryConnection",
"Name": "Openable"
}
},{
"instanceId": "RepositoryConnection.SupportsWindowsIntegratedAuthentication--Repositories.RepositoryIdentifier. Bentley.PW--RepoServerName~3ARepoName",
"className": "PolicyAssertion",
"schemaName": "Policies",
"eTag": "tQY+z6jwtAma99ylJLE7XkcEtY0=",
"properties": {
"Supported": false,
"ServiceType": "RepositoryConnection",
"Name": "SupportsWindowsIntegratedAuthentication"
}
},
...
]
}
Example 4
Query for all policy assertions for a specified repository’s connection.
This request maps to the ECService.GetRepositoryConnectionPolicy method call.
GET v2.5/Repositories/{repositoryId}/Policies/PolicyAssertion
Example 5
Query for all persistence service policy assertions for a specified repository’s connection for specified class.
This request maps to the PersistenceService.GetClassPolicy method call.
Example 6
Query for all policy assertions for a specified repository’s connection for specified instances.
This request maps to the ECService.GetInstancePolicy method call.
PresentationRuleSet is a list of rules that define tree hierarchy and content provided by RuleDrivenPresentationECPlugin. To setup a presentation rule set in Bentley Web Services Gateway, add the following configuration to the ecom.config file:
<PresentationRuleSets>
<RuleSetLocatersForPlugin pluginId="<Plugin ID>">
<RuleSets>
<Path><Relative path to PresentationRuleSet.xml ></Path>
</RuleSets>
</RuleSetLocatersForPlugin>
</PresentationRuleSets>
Where "<Plugin ID>" is your plugin identifier and "<Relative path to PresentationRuleSet.xml >" is the relative path from ecom.config to the presentation rule set file.
More information about PresentationRuleSet format can be found in the EC Framework documentation.
Since: 2.7
Asynchronous request allows starting execution of the requests at some time in future.
To enable asynchronous request execution, it must be configured on the server side.
To initialize one, we must add 'Mas-Async-Job' header with value, that indicates whether asynchronousness is required or optional. Possible values:
Supported HTTP methods for asynchronous request are:
Request header example:
Mas-Async-Job:Force
Header and it's values are case insensitive, but if value is misspelled server will result in 400 (Bad Request) error status response.
Request result:
When request is executed asynchronously, we will get empty response body, but response headers will contain 'Operation-Location' header.
'Operation-Location' header value will contain request message, that would query for asynchronous request result:
Operation-Location: https://localhost/v2.7/Repositories/{repositoryId}/Jobs/Job/{asynconousRequestResultId}
It is allowed just to 'GET' or 'DELETE' result class instances.
Request structure:
https://localhost/v2.7/Repositories/{repositoryId}/Jobs/Job/{asynconousRequestResultId}
Response structure:
{
"instances": [
{
"instanceId": "{asynchonousRequestResultId}",
"schemaName": "Jobs",
"className": "Job",
"properties": {
"Status": "Succeeded",
"ResponseStatusCode": 201,
"ResponseContent": "{"changedInstance":{"change":"Created","instanceAfterChange":{"instanceId":"4e207b21-2916-4f85-a1b7-c8fc....properties":{"DocumentName":"jkljk"}}}}",
"ResponseHeaders": "Pragma: no-cache\nMas-License-Error-Id: NoClientLicense\n....Connection: close\n",
"StartTime": "2000-01-01T13:44:01.2349987Z",
"ScheduleTime": "2000-01-01T13:43:57.3126099Z",
"CompleteTime": "2000-01-01T13:44:01.6563628Z"
},
"eTag": "{eTagValue}"
}
]
}
Result instance properties:
Status |
Possible values:
If value is 'NotStarted' neither the property 'ResponseStatusCode' or 'ResponseContent' or 'ResponseHeaders' or 'StartTime' or 'CompleteTime' are being set. If value is 'Running' property 'StartTime' will be set. If value is 'Failed' property 'CompleteTime' will be set. If value is 'Succeeded' all properties will be set. |
ResponseStatusCode |
If set, it will be one of (HTTP) response status codes. |
ResponseContent |
If asynchronous request sent successfully will contain the response body from the sent synchronous request. |
ResponseHeaders |
If asynchronous request sent successfully will contain the response headers from the sent synchronous request. |
ScheduleTime |
Always set. Datetime when asynchronous request was sent. |
StartTime |
If set, indicates when asynchronous request is started to execute, otherwise not started. |
CompleteTime |
If set, indicates when asynchronous request is finished to execute, otherwise not finished. |
Example 1:
Result of not started syncronous request.
Request:
GET https://localhost/ws/v2.7/Repositories/Bentley.PW--PW/Jobs/Job/552ae4c6-f2d3-490d-9b88-ff9f49b3ac53
Response:
{
"instances": [
{
"instanceId": "552ae4c6-f2d3-490d-9b88-ff9f49b3ac53",
"schemaName": "Jobs",
"className": "Job",
"properties": {
"Status": "NotStarted",
"ScheduleTime": "2000-01-01T13:43:57.3126099Z"
},
"eTag": "{eTagValue}"
}
]
}
Example 2:
Result of started asyncronous request.
Request:
GET https://localhost/ws/v2.7/Repositories/Bentley.PW--PW/Jobs/Job/6b39f111-e38e-41b2-bf33-1c9b2a0965e1
Response:
{
"instances": [
{
"instanceId": "6b39f111-e38e-41b2-bf33-1c9b2a0965e1",
"schemaName": "Jobs",
"className": "Job",
"properties": {
"Status": "Running",
"StartTime": "2000-01-01T13:44:01.2349987Z",
"ScheduleTime": "2000-01-01T13:43:57.3126099Z"
},
"eTag": "{eTagValue}"
}
]
}
Example 3:
Result of failed asyncronous request.
Request:
GET https://localhost/ws/v2.7/Repositories/Bentley.PW--PW/Jobs/Job/96fec14e-61ed-41a4-a8e8-7831b173e5f6
Response:
{
"instances": [
{
"instanceId": "96fec14e-61ed-41a4-a8e8-7831b173e5f6",
"schemaName": "Jobs",
"className": "Job",
"properties": {
"Status": "Failed",
"StartTime": "2000-01-01T13:44:01.2349987Z",
"ScheduleTime": "2000-01-01T13:43:57.3126099Z",
"CompleteTime": "2000-01-01T13:44:01.6563628Z"
},
"eTag": "{eTagValue}"
}
]
}
Copyright © 2018 Bentley Systems, Incorporated. All rights reserved.