Synchronize a file from iTwin Storage

Introduction

This is a walk-through of how to synchronize a file from iTwin Storage to an iModel using Synchronization API. Synchronization API works in iTwin 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

Prerequisites

This tutorial assumes that you:

  • Already have a tool such as Postman that can be used to execute HTTP calls. These calls can also be made using the Try it out button in the API documentation or any other HTTP request tool.
  • Familiar with concepts of Authorization, iModel, iTwin, Project & Storage.
  • Have created a iTwin and have its ITWIN_ID. You can create a iTwin using iTwins API.
  • Have files uploaded inside the iTwin (or Project) by using previously created ITWIN_ID or PROJECT_ID. If you do not have files in the Storage, follow Storage API tutorial or consult with Storage API documentation. You may use generated ITWIN_ID instead of PROJECT_ID in Storage API endpoints.
If you have already created a project with files inside it - you may use PROJECT_ID instead ITWIN_ID in this tutorial.

1. Preparing to use Synchronization API

There are some actions, which should be completed before starting using Synchronization API.

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.

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 Storage Connection
  2. Click “Try it out” 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.

2. 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.

Note that this step assumes that You already have a ITWIN_ID from previously created iTwin.

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.

You can execute the request on the iModel API Documentation page, “Try it out” section.

HTTP
POST https://api.bentley.com/imodels HTTP/1.1
Authorization: Bearer JWT_TOKEN
Content-Type: application/json
Accept: application/vnd.bentley.itwin-platform.v2+json

There are two required properties for the create iModel payload.

name - iModel name is required which uniquely identifies the iModel within the Project.
iTwinId - provides iTwin identifier that created iModel will belong to. iTwin 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 the specification of 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 into the area of interest in web viewers.

If you get a response code 404 with the message "Requested iTwin is not available.", Please check if App or User has access to the iTwin.
Note that after completing this step, you will be provided with an IMODEL_ID which will be required in later steps.
JSON
{
      "iTwinId": "ITWIN_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
          }
        }
    }

3. Get FILE_ID 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=ITWIN_ID request.

You can execute the request on the Storage API Documentation page, “Try it out” section.

Requirements:

  1. Authorization header with valid Bearer token is required.
  2. ITWIN_ID where files and folders are stored.
HTTP
GET https://api.bentley.com/storage/?projectId=ITWIN_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"
        }
    }
}

4. 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.

To create a connection, send a POST request to the synchronization/imodels/storageConnections endpoint.

You can execute the request on the Synchronization API Documentation page, “Try it out” section.

Requirements:

  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 - identifier of the connector used to process the file. For more information, see Supported formats.
    • [Optional] authenticationType - defaults to User and uses a refresh token to get an access token for long synchronizations. But it can be set to Service when API is used from server application without user context.
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",
        "iTwinId": "ITWIN_ID",
        "_links": {
            "iModel": {
                "href": "https://api.bentley.com/imodels/IMODEL_ID"
            },
            "iTwin": {
                "href": "https://api.bentley.com/itwins/ITWIN_ID"
            },
            "lastRun": null
        }
    }
}

5. 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.

Note that if connection authenticationType is set to Service this step should be skipped.

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

You can execute the request on the Synchronization API Documentation page, “Try it out” section.

  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"
            }
        }
    }
}

6. Run a Connection

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

Send a POST request to the synchronization/imodels/connections/{connectionId}/runs endpoint with valid connectionId to run a connection.

You can execute the request on the Synchronization API Documentation page, “Try it out” section.

  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

7. 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.

You can execute the request on the Synchronization API Documentation page, “Try it out” section.

  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"
    }
  }
}

8. Synchronize an updated file

If a file is changed on iTwin storage, it has to be synchronized again for the iModel to be updated. The workflow should be:

  1. File is updated on iTwin Storage.
  2. Run the connection again. (See step 7)
  3. Get connection run status. (See step 8)

8. Conclusion

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

  1. Create a connection
  2. Run the connection
  3. 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.