Synchronize a file from iTwin Storage

Introduction

This is a walk-through how to synchronize a file from iTwin Storage to an iModel using Synchronization API. Synchronization API works in project and iModel context. To synchronize a set of files a connection has to be created. Connection is an aggregation of properties like file metadata which is needed for synchronization. Connections can be run on demand which starts a file specified in the connection conversion to an iModel.

Info

Skill level:

Basic

Duration:

30 minutes

1. Register an Application

You will need to register an application to use the iTwin Platform APIs. You can use the Register button to automatically create your first single page application (SPA). This will allow you to configure Authorization Code Flow for your SPA application and get the correct access token.

Once generated, you will be shown a few lines of code under the button.

  • IMJS_AUTH_CLIENT_CLIENT_ID - this is the unique identifier for your application. Displayed on application details page as Client ID.
  • IMJS_AUTH_CLIENT_REDIRECT_URI - specifies where users are redirected after they have chosen whether or not to authenticate your app. Displayed on application details page as one of Redirect URIs.
  • IMJS_AUTH_CLIENT_LOGOUT_URI - specifies where users can be returned to after logging out. Displayed on application details page as one of Post logout redirect URIs.
  • IMJS_AUTH_CLIENT_SCOPES - list of accesses granted to the application. Displayed on application details page as Scopes.

Or optionally: Register and configure your application manually following instructions in Register and modify an Application tutorial. Make sure that your application is associated with Synchronization, iModels and Storage APIs and has synchronization:read synchronization:modify imodels:read imodels:modify storage:read scopes enabled.

Requires you to sign in. Will automatically generate a Single page application (SPA) that is required to complete this tutorial. You will be able to manage your SPA from your My apps page.

2. Get a token

To make request to API user token is needed. There are several ways to get it.

Follow this article to implement Authorization code workflow in your application.

  1. Go to Create Connection - Synchronization
  2. Click “Try it” button.
  3. On Authorization section select “AuthorizationCode”.
  4. After popup closes Authorization header with token value should be visible.
  5. Save token value for this tutorial.

3. Create an iModel

An iModel is a specialized information container for exchanging data associated with the lifecycle of infrastructure assets. iModels were created to facilitate the sharing and distribution of information regardless of the source and format of the information.

iTwin Platform iModels API is based on iModelHub cloud service which enables alignment, accountability and accessibility of infrastructure digital twins. It is the control center for iModels and is responsible for coordinating concurrent access to iModels as well as changes made to them.

An empty iModel is created by sending a HTTP POST message to https://api.bentley.com/imodels/ endpoint with the payload describing the iModel to be created.

HTTP
POST https://api.bentley.com/imodels HTTP/1.1
Authorization: Bearer JWT_TOKEN
Content-Type: application/json

There are two required properties for the create iModel payload.

name - iModel name is required which uniquely identifies the iModel within the Project.
projectId - provides Project identifier that created iModel will belong to. Project identifier is a required property.
description - free form text field so you could give more information about the iModel.
extent - iModels usually are placed at some location on the Earth. This property allows to specify the maximum rectangular area on the Earth which encloses the iModel. The maximum extent is used to help keep your iModel clean. When new elements are imported, those outside the extent will be flagged for further processing. This extent will also help to zoom to the area of interest in web viewers.

Note that after completing this step, you will be provided with both a PROJECT_ID (i.e. ProjectId) and an iModel_ID which will be required in a later step.
JSON
{
      "projectId": "PROJECT_ID",
      "name": "Sun City Renewable-energy Plant",
      "description": "Overall model of solar farms in Sun City",
      "extent": {
          "southWest": {
            "latitude": 46.13267702834806,
            "longitude": 7.672120009938448
          },
          "northEast": {
            "latitude": 46.302763954781234,
            "longitude": 7.835541640797823
          }
        }
    }

4. Get fileId from Storage API

iTwin File Storage API store files and folders under some folder. To get root files and folder we can use “Get top level folders and files by project” API.

That can be done by sending a GET https://api.bentley.com/storage/?projectId=PROJECT_ID request.

  1. Authorization header with valid Bearer token is required.
  2. PROJECT_ID where files and folders are stored.
HTTP
GET https://api.bentley.com/storage/?projectId=PROJECT_ID HTTP/1.1
Authorization: Bearer JWT_TOKEN
Content-Type: application/json

The request response contains a file Id which will be used in next step.

JSON
{
    "items": [{
        "id": "FOLDER_ID",
        "type": "folder",
        "displayName": "1",
        "description": null,
        "path": "1",
        "lastModifiedByDisplayName": "Joe User",
        "createdDateTime": "2019-07-16T08:41:05.6415752Z",
        "lastModifiedDateTime": "2020-01-07T08:46:47.5422276Z",
        "parentFolderId": "mCbnk2CSr0K4bAkoDGgNEZgm55Ngkq9CuGwJKAxoDRE",
        "_links": {
            "createdBy": {
                "href": "https://api.bentley.com/projects/6959daff-27f5-4b87-96ea-9917daa3a8ff/members/4ebeaf72-3c42-4734-b41a-485c6c2ecb67"
            },
            "lastModifiedBy": {
                "href": "https://api.bentley.com/projects/6959daff-27f5-4b87-96ea-9917daa3a8ff/members/4ebeaf72-3c42-4734-b41a-485c6c2ecb67"
            },
            "parentFolder": {
                "href": "https://api.bentley.com/storage/folders/mCbnk2CSr0K4bAkoDGgNEZgm55Ngkq9CuGwJKAxoDRE"
            }
        }
    },{
        "id": "FILE_ID",
        "type": "file",
        "displayName": "Test.dgn",
        "description": null,
        "path": "Test.dgn",
        "size": "38400",
        "lastModifiedByDisplayName": "Joe User",
        "createdDateTime": "2020-06-23T11:13:42.3498148Z",
        "lastModifiedDateTime": "2020-07-07T11:46:44.9573652Z",
        "parentFolderId": "mCbnk2CSr0K4bAkoDGgNEZgm55Ngkq9CuGwJKAxoDRE",
        "_links": {
            "createdBy": {
                "href": "https://api.bentley.com/projects/6959daff-27f5-4b87-96ea-9917daa3a8ff/members/4ebeaf72-3c42-4734-b41a-485c6c2ecb67"
            },
            "lastModifiedBy": {
                "href": "https://api.bentley.com/projects/6959daff-27f5-4b87-96ea-9917daa3a8ff/members/4ebeaf72-3c42-4734-b41a-485c6c2ecb67"
            },
            "parentFolder": {
                "href": "https://api.bentley.com/storage/folders/mCbnk2CSr0K4bAkoDGgNEZgm55Ngkq9CuGwJKAxoDRE"
            }
        }
    }],
    "_links": {
        "self": {
            "href": "https://api.bentley.com/storage?projectId=PROJECT_ID&$skip=0&$top=100"
        },
        "prev": {
            "href": "https://api.bentley.com/storage?projectId=PROJECT_ID&$skip=0&$top=100"
        },
        "next": {
            "href": "https://api.bentley.com/storage?projectId=PROJECT_ID&$skip=100&$top=100"
        },
        "folder": {
            "href": "https://api.bentley.com/storage/folders/mCbnk2CSr0K4bAkoDGgNEZgm55Ngkq9CuGwJKAxoDRE"
        }
    }
}

5. Create a Connection

The synchronization process is based on connections that establish links from design files to iModels. There could be multiple connections for an iModel, and those could be executed on-demand multiple times to synchronize changes. In this step we will be creating such connection.

Creating a Connection requires sending a POST request to the synchronization/imodels/storageConnections endpoint.

  1. Authorization header with valid Bearer token is required.
  2. IMODEL_ID of created iModel from step 3.
  3. We will need to specify what file from File Storage should be mapped to a connection. To do that we will need a file id from previous step response.
HTTP
POST https://api.bentley.com/synchronization/imodels/storageConnections HTTP/1.1
Authorization: Bearer JWT_TOKEN
Content-Type: application/json
  • displayName - user facing connection name
  • iModelId: - iModel Id which should contain created connection
  • sourceFiles - information about source files from File Storage
    • storageFileId - id of the file from Storage API
    • connectorType - connector which file should be processed with identifier. More information.
JSON
{
    "displayName": "Connection1",
    "iModelId": "IMODEL_ID",
    "sourceFiles": [{
        "storageFileId": "FILE_ID",
        "connectorType": "MSTN"
    }]
}

The request response contains created connection properties values. Id is going to be needed in next step

JSON
{
    "connection": {
        "id": "CONNECTION_ID",
        "displayName": "connection1",
        "iModelId": "IMODEL_ID",
        "projectId": "PROJECT_ID",
        "_links": {
            "iModel": {
                "href": "https://api.bentley.com/imodels/IMODEL_ID"
            },
            "project": {
                "href": "https://api.bentley.com/projects/PROJECT_ID"
            },
            "lastRun": null
        }
    }
}

6. Store refresh token for user

The synchronization process usually takes time and is performed in the background. For that, we need to store the connection owner’s refresh token. You can get it by using Get Authorization Information API. This API will return the current status and a redirect URL where user has to be redirected on the browser if the token has to be renewed.

That can be done by sending a GET https://api.bentley.com/synchronization/imodels/connections/authorizationInformation?redirectUrl=REDIRECT_URL request.

  1. Authorization header with valid Bearer token is required.
  2. REDIRECT_URL a url of where a user should be redirected after successful token renewal.
HTTP
GET https://api.bentley.com/synchronization/imodels/connections/authorizationInformation?redirectUrl=REDIRECT_URL HTTP/1.1
Authorization: Bearer JWT_TOKEN
Content-Type: application/json

isUserAuthorized with value true, means that user has a valid refresh token and can run long running synchronizations.

JSON
{
    "authorizationInformation": {
        "isUserAuthorized": true,
        "_links": {
            "authorizationUrl": {
                "href": null
            }
        }
    }
}

isUserAuthorized with value false, means that user does not have valid refresh token and cannot run long running synchronizations. To refresh token user has to be redirected to authorizationUrl from response.

JSON
{
    "authorizationInformation": {
        "isUserAuthorized": false,
        "_links": {
            "authorizationUrl": {
                "href": "https://connect-itwinbridgeportal.bentley.com/authenticate?redirect_url=REDIRECT_URL"
            }
        }
    }
}

7. Run a Connection

A Run defines a single Connection synchronization process. It can be initialized manually by sending run start request.

Running a connection requires sending a POST request to the synchronization/imodels/connections/{connectionId}/run[?imodelId] endpoint with valid connectionId.

  1. Authorization header with valid Bearer token is required.
  2. CONNECTION_ID which should be started for processing. Use the value from previous step response.
HTTP
POST https://api.bentley.com/synchronization/imodels/storageConnections/CONNECTION_ID/run HTTP/1.1
Authorization: Bearer JWT_TOKEN
Content-Type: application/json

On successful request, operation returns http status code 202/accepted - the request is accepted for processing and will be executed in the background. If there is already an active run in progress for this connection, new run is being added to the queue.

HTTP
HTTP/1.1 202 Accepted

8. Get runs statuses

A run contains synchronization process status. To get runs history and statuses get request has to be made.

Getting Run status requires sending a GET request to the synchronization/imodels/storageConnections/{connectionId}/runs endpoint with valid connectionId.

  1. Authorization header with valid Bearer token is required.
  2. CONNECTION_ID which runs we want to get.
HTTP
POST https://api.bentley.com/synchronization/imodels/storageConnections/CONNECTION_ID/runs HTTP/1.1
Authorization: Bearer JWT_TOKEN
Content-Type: application/json
Response

At the end of synchronization run state should be “Completed” and result “Success”.

JSON
{
  "runs":[
    {
      "id":"41062244-3e62-42a3-8232-9f2b4d31be16",
      "state":"Completed",
      "result":"Success"
    }
  ],
  "_links":{
    "self":{
      "href":"https://api.bentley.com/Synchronization/imodels/storageConnections/CONNECTION_ID/runs?$skip=0&$top=100"
    },
    "prev":{
      "href":"https://api.bentley.com/Synchronization/imodels/storageConnections/CONNECTION_ID/runs?$skip=0&$top=100"
    },
    "next":{
      "href":"https://api.bentley.com/Synchronization/imodels/storageConnections/CONNECTION_ID/runs?$skip=100&$top=100"
    }
  }
}

9. Conclusion

In this tutorial we have gone through a file from iTwin Storage synchronization process:

  1. Create an empty iModel
  2. Create a connection
  3. Run the connection
  4. Get run status.

After successful run, design file changes should be in an iModel. Next step could be to create a Named Version.

Continue learning

Congratulations for the completion of your first synchronization! You’ve now know a lot on the subject, but there’s still possibilities to learn more to unleash the platform capabilities.

More resources that you may like

An overview and detailed Synchronization API documentation.
A working code sample showing how Synchronization API can be integrated into a React application.
An overview and detailed Data Management API documentation.