15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RPA (Robotic Process Automation)Advent Calendar 2019

Day 13

UiPath Orchestrator Community Edition のAPIを呼び出す件と、カスタムアクティビティをつくってみた

Last updated at Posted at 2019-12-12

UiPath Orchestrator Community Edition へのサインアップからHelloWorldまで。」をかきつつUiPath OrchestratorのCommunity Edition(以下OC)をあらためてさわってみたところ、アカウントとテナントの考え方?が変わっていたり、いろんな機能が追加されていたり、、。

アカウント/テナントの考え方が変わったのは半年くらい前から気づいてはいたものの、よくみるとAPI仕様もなにやら変わっているようで、ちょっと整理しておこうと思います。
あ、ちなみにAPIとは https://platform.uipath.com/[AccountLogicalName]/[ServiceName]/swagger/ で公開されているRESTのAPIのことです。

例: https://platform.uipath.com/kinooqmollho/kinoorgDefault/swagger/ ← いつかリンク切れるかも。。

TL;DR

  • いままでの「テナント名/ユーザID/パスワード」でログインするやりかた https://platform.uipath.com/api/Account/Authenticateはうまく動かすことが出来ませんでした、、。
  • そのかわり、OCの画面で確認できる**「User Key/Client Id」でアクセストークンを取得するやりかたで、APIを利用する**ことができました。
  • RobotからAPIを叩く場合はもちろん「Orchestrator への HTTP 要求」アクティビティを利用するのが簡単です。Robotに、操作対象のCRUDする権限をつける必要がありますが。

というわけで、今回はRobotからAPIを叩く場合以外も想定して「Orchestrator への HTTP 要求」アクティビティを使わない方法での疎通確認を行います。

認証の仕様が変わった??

さてさっそく。。シンプルに curl から実行してみます。先のSwaggerをみてもわかるとおり認証のI/Fは、下記のJSONデータを投げればよいようです。。

{
  "tenancyName":"xxx",
  "usernameOrEmailAddress":"xxx",
  "password":"xxx"
}

というわけでやってみます。

$ curl https://platform.uipath.com/kinooqmollho/kinoorgDefault/api/Account/Authenticate \
-H 'Content-Type:application/json' \
-X POST \
--data '{"tenancyName":"xxx","usernameOrEmailAddress":"xxx","password":"xxx"}'

実行結果は、、

{"message":"Invalid credentials, failed to login.","errorCode":1000,"resourceIds":null}

ダメでした。。そもそもテナント名をなににするのか?って話もありますが、

  • 画面に表示されてるサービス名 「kinoorgDefault」(ServiceName とか serviceInstanceName とかいうらしい。後述)
  • Tenant Logical Name:「kinoorgDefaean0252851」(後述)
  • Account Logical Name「kinooqmollho」(後述)
  • オンプレで構築時のデフォルトのテナント名「Default」
  • tenancyName 指定せず

など、さまざまやってみましたが、全部ダメでした。おなじエラーコードが返ります。うーん、これでOKだった頃もあったハズなんだけどなぁ、、。
というわけでアカウントでログインする方法は一旦やめ。方針変更です。

ググってみると、、

ところでググってみると、こんな情報が。Consuming Cloud API

All clients that used to connect to Orchestrator CE via API, or using PowerShell and other scripting tools, need to be updated in order to connect to the UiPath Cloud Platform.

なんとOrchestrator CE 向けのAPIは仕様が変更されてる模様。。Swaggerにも書いておいてほしかった、、、。

気を取り直して、いわゆるOAuthによるトークン取得の方法でいきます。

まずはアクセストークン取得

OC画面より「User Key/Client Id」を取得

自分のOC画面にログインし、左メニューの「サービス」を選択します。
001.png
右部メニューより「API Access」を選択
002.png
表示された**「User Key/Client Id」をメモ**っておきます。
003.png

また**「Tenant Logical Name」も使用するのでメモ**しておきましょう。

アクセストークンの取得

さて先のリンク先のドキュメントの仕様どおり[User Key],[Client Id]を使って、トークンを取得します。

$ curl -X POST https://account.uipath.com/oauth/token  \
-H 'Content-Type:application/json' \
--data '{"grant_type": "refresh_token", "client_id": "[Client Id]", "refresh_token": "[User Key]"}'

結果は、、、

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJUTkVOMEl5T1RWQk1UZEVRVEEzUlRZNE16UkJPVU00UVRRM016TXlSalUzUmpnMk4wSTBPQSJ9.eyJodHRwczovL3VpcG...割愛",
  "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJUTkVOMEl5T1RWQk1UZEVRVEEzUlRZNE16UkJPVU00UVRRM016TXlSalUzUmpnMk4wSTBPQSJ9.eyJodHRwczovL2Nsb3Vkcn...割愛",
  "scope": "openid profile email offline_access",
  "expires_in": 86400,
  "token_type": "Bearer"
}

access_tokenとid_token が取得できました。access_token はつぎで使うので、メモっておきましょう。あ、id_tokenももう少し先で使用しますので、そいつもメモっときます。

ちなみにトークンの値は上記は全部載せてませんが、JWTの仕様にしたがってPayload部(ドッドで区切った二つ目の文字列)をデコードしてみると、、、

$ echo eyJodHRwczovL2Nsb3VkcnBhL3VzZXJpbmZvIjp7IndlbGNvbWVFbWFpbFN0YXR1cyI6IlBFTkR........ | base64 -D 
{
  "https://cloudrpa/userinfo": {
    "welcomeEmailStatus": "PENDING",
    "firstName": "Masatomi",
    "lastName": "KINO",
    "marketingConditionAccepted": "false",
    "user_signup_language": "ja",
    "termsAndConditionsAccepted": "true",
    "country": "Japan",
    "companyName": "ki-no.org",
    "applications": [
      "51eXCxxxxxxxxx"
    ]
  },
  "nickname": "uipath-friends",
  "name": "uipath-friends@xxxxx.org",
  "picture": "https://s.gravatar.com/avatar/c9911ba86d95bb47cd53ec59e8d2418a?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fui.png",
  "updated_at": "2019-12-11T08:57:56.655Z",
  "email": "uipath-friends@xxxxx.org",
  "email_verified": true,
  "iss": "https://account.uipath.com/",
  "sub": "auth0|5dexxxxx",
  "aud": "8DEvxxxx",
  "iat": 1576054721,
  "exp": 1576090721
}

こんな感じの情報が含まれてることがわかります。

API使用例

先ほど取得した**「access_token」とメモしておいた「Tenant Logical Name」を使って**APIを呼び出してみます。
ちなみにAPI仕様の詳細はSwaggerで、また使用例は https://docs.uipath.com/orchestrator/lang-ja/reference#users-requests この辺にあったりします。

例:ライセンス情報を取得する

はじめなのでI/F仕様をちゃんとかくと

$ curl 'https://platform.uipath.com/[Account Logical Name]/[ServiceName]/odata/Settings/UiPath.Server.Configuration.OData.GetLicense'  \
-H 'X-UiPath-TenantName: [Tenant Logical Name]' \  
-H 'Authorization: Bearer [access_token]'

となります。具体的な値をいれると

$ curl https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/Settings/UiPath.Server.Configuration.OData.GetLicense  \
-H 'X-UiPath-TenantName: kinoorgDefaean0252851' \  
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSU...割愛'

こうです。さて、実行結果は、、

{
  "@odata.context": "https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/$metadata#UiPath.Orchestrator.Application.Dto.License.LicenseDto",
  "HostLicenseId": null,
  "Id": 81837,
  "ExpireDate": 1638403199,
  "GracePeriodEndDate": 1638403199,
  "GracePeriod": null,
  "AttendedConcurrent": false,
  "DevelopmentConcurrent": false,
  "StudioXConcurrent": false,
  "LicensedFeatures": [],
  "IsRegistered": true,
  "IsExpired": false,
  "CreationTime": "2019-12-02T06:08:58.33Z",
  "Code": "db8adeff-xxx-xxx-xxx-xxxx",
  "Allowed": {
    "Unattended": 1,
    "Attended": 2,
    "NonProduction": 0,
    "Development": 2,
    "StudioX": 0
  },
  "Used": {
    "Unattended": 0,
    "Attended": 1,
    "NonProduction": 0,
    "Development": 1,
    "StudioX": 0
  }
}

OCのCommunity版上で取得したライセンスの情報がとれましたね。。

例:ユーザ情報を取得する

FullNameが'Masatomi KINO'なユーザを検索してみます。

$ cat param.txt 
$filter=FullName eq 'Masatomi KINO'
$

というファイルをつくっておき、それをクエリパラメタにのせてAPIを呼び出します。

$ curl -G 'https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/Users' \
--data-urlencode @param.txt \
-H 'X-UiPath-TenantName: kinoorgDefaean0252851' \
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSU...割愛'

結果は、

{
  "@odata.context": "https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/$metadata#Users",
  "@odata.count": 1,
  "value": [
    {
      "Name": "Masatomi",
      "Surname": "KINO",
      "UserName": "admin",
      "Domain": null,
      "FullName": "Masatomi KINO",
      "EmailAddress": "uipath-friends@xxxx.org",
      "IsEmailConfirmed": false,
      "LastLoginTime": "2019-12-12T01:48:46.38Z",
      "IsActive": true,
      "CreationTime": "2019-12-02T06:08:57.3Z",
      "AuthenticationSource": null,
      "Password": null,
      "IsExternalLicensed": false,
      "RolesList": [
        "Administrator"
      ],
      "LoginProviders": [],
      "TenantId": 1234,
      "TenancyName": null,
      "TenantDisplayName": null,
      "TenantKey": null,
      "Type": "User",
      "ProvisionType": "Manual",
      "LicenseType": null,
      "Key": "xxx-76c9-xxx-95ff-xxx",
      "MayHaveUserSession": true,
      "MayHaveRobotSession": true,
      "BypassBasicAuthRestriction": false,
      "Id": 118691,
      "RobotProvision": null,
      "NotificationSubscription": {
        "Queues": true,
        "Robots": true,
        "Jobs": true,
        "Schedules": true,
        "Tasks": true,
        "QueueItems": true
      }
    }
  ]
}

指定したユーザのユーザ情報が取得できました。ちなみにクエリパラメタにのせる検索条件は API リクエストの構築 ここに記載されています。

蛇足ですが、もはやUiPathの話しじゃないですが、

--data-urlencode @param.txt

をむりやりコンソール上で書くと、

--data-urlencode '$filter=FullName eq '\''Masatomi KINO'\''' \

って'\'でエスケープしてください1
参考:【シェルスクリプト】クォートの使い分け方

例:タスクをアサインする

UiPath Orchestrator 2019.10から?の新機能、タスクもAPIが用意されています。まずは未アサインのタスクを探してみます

$ cat param.txt
$filter=Status eq 'Unassigned'
$
$ curl -G 'https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/Tasks' \
--data-urlencode @param.txt \
-H 'X-UiPath-TenantName: kinoorgDefaean0252851' \
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSU...割愛'

実行結果:

{
  "@odata.context": "https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/$metadata#Tasks",
  "@odata.count": 2,
  "value": [
    {
      "Title": "お休みのお伺い",
      "Type": "FormTask",
      "Priority": "Medium",
      "Status": "Unassigned",
      "CreationTime": "2019-12-11T04:51:00.373Z",
      "TaskCatalogName": "TaskTest",
      "OrganizationUnitId": 83120,
      "IsCompleted": false,
      "Id": 420
    },
    {
      "Title": "お休みのお伺い",
      "Type": "FormTask",
      "Priority": "Medium",
      "Status": "Unassigned",
      "CreationTime": "2019-12-11T06:17:11.347Z",
      "TaskCatalogName": "TaskTest",
      "OrganizationUnitId": 83120,
      "IsCompleted": false,
      "Id": 427
    }
  ]
}

"Status": "Unassigned" なタスクが検索できましたね。"Id": 420 などタスクIDも確認できました。

つぎにアサインですが、アサインのAPIに必要なユーザIDがさきほどのユーザ情報取得APIで "Id": 118691 などと取得できていることを使って、下記の通りAPIをコールします。

$ curl -X POST 'https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/Tasks/UiPath.Server.Configuration.OData.AssignTasks' \
--data '{ "taskAssignments": [ { "TaskId": 420, "UserId": 118691 }] }' \
-H 'Content-Type:application/json' \
-H 'X-UiPath-TenantName: kinoorgDefaean0252851' \
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSU...割愛'

結果:

{
  "@odata.context": "https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/$metadata#Collection(UiPath.Orchestrator.Tasks.Dto.TaskAssignmentErrorResponse)",
  "value": []
}

ゼロ件が返ってくるとOKぽいです。画面で確認すると、、
assign.png

ちゃんとアサインされてますねーー。。

ちなみに、すでにアサイン済みのタスクを再度アサインする(つまり同じコマンドを再度実行する)と下記のようなエラーになりました。

{
  "@odata.context": "https://platform.uipath.com/kinooqmollho/kinoorgDefault/odata/$metadata#Collection(UiPath.Orchestrator.Tasks.Dto.TaskAssignmentErrorResponse)",
  "value": [
    {
      "TaskId": 420,
      "UserId": 118691,
      "ErrorCode": 2400,
      "ErrorMessage": "タスクは既に割り当てられています"
    }
  ]
}

戻り電文の内容をみることで、エラーが発生しているかを確認できそうですね。

ほかにもたくさんのAPIがあるので、ぜひ遊んでみてください。

APIのURLにある「Account Logical Name」「ServiceName」や、ヘッダにのせる「Tenant Logical Name」も取得したい

さてさて、APIのURLの一部や HTTPヘッダに載せていた、

  • 画面に表示されてる ServiceName (serviceInstanceName):「kinoorgDefault」
  • Tenant Logical Name:「kinoorgDefaean0252851」
  • Account Logical Name「kinooqmollho」

なども自動で取得できたら便利です。UiPath社の公式の仕様は見つからなかったのですが、UiPath社が書いている記事にこんなのがありました。

Microsoft Flow と UiPath Orchestrator の連携方法

上記の情報を取得するには、先ほど取得してまだ使っていなかった「id_token」をつかいます。

Account Logical Name を取得する

Authorization: Bearer [id_token] って、今回は「id_token」を使います。「access_token」ではないのでご注意ください。

$ curl https://platform.uipath.com/cloudrpa/api/getAccountsForUser \
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJUTkVOMEl5T1RWQk1UZEVRVEEzUlRZNE16UkJPVU00UVRRM016TXlSalUzUmpnMk4wSTBPQSJ9.eyJodHRwczovL2Nsb3VkcnB...割愛'
{
  "userEmail": "uipath-friends@xxx",
  "accounts": [
    {
      "accountName": "xxx.org",
      "accountLogicalName": "kinooqmollho"
    }
  ]
}

"accountLogicalName": "kinooqmollho" が「Account Logical Name」です。

ServiceName,Tenant Logical Name を取得する

つづいて「ServiceName」「Tenant Logical Name」です。
URLに、先ほど取得した「accountLogicalName」 の値を使用しつつ、またふたたび「id_token」を利用します。

(URLに「accountLogicalName」が含まれてることに注意して、、、)
$ curl https://platform.uipath.com/cloudrpa/api/account/kinooqmollho/getAllServiceInstances \
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJUTkVOMEl5T1RWQk1UZEVRVEEzUlRZNE16UkJPVU00UVRRM016TXlSalUzUmpnMk4wSTBPQSJ9.eyJodHRwczovL2Nsb3VkcnB...割愛'
[
  {
    "serviceInstanceName": "kinoorgDefault",
    "serviceInstanceLogicalName": "kinoorgDefaean0252851",
    "serviceType": "ORCHESTRATOR",
    "serviceUrl": "https://crpa-prod-orch0-ne-webapp.azurewebsites.net",
    "serviceState": "ENABLED",
    "userRolesInService": [
      "Administrator"
    ]
  }
]

"serviceInstanceName": "kinoorgDefault"が「ServiceName」、
"serviceInstanceLogicalName": "kinoorgDefaean0252851"が「Tenant Logical Name」です。

これらの値は画面上で確認ができるので、APIで取得できなくてもまあ問題はないのですが**「User Key/Client Id」さえあればAPIで取得できる**ことがわかりました。。

おまけ(カスタムアクティビティ開発)

おまけです。
APIを利用したカスタムアクティビティをつくってみました。

インストール

[NuGet] (https://www.nuget.org/packages/kino.UiPath.OrchestratorAPI/)にアップしたので**UiPath Studio上で「kino.uipath」って検索すれば**出てくると思います。

004.png

もし nuget.orgの フィードがなかったら「パッケージを管理>> (左上の)設定」から、パッケージ取得元のソースに https://api.nuget.org/v3/index.json を追加してください。

使い方

つくったアクティビティはたとえばこんな感じです。例のOC画面に表示される**「User Key/Client Id」** をプロパティにセットして使用します。
005.png

AssignTaskアクティビティは、作成したタスクのタスクIDを使って、指定したユーザにそのタスクをアサインします。

user_key/clientId は画面上のモノを。fullNameはさきほど検索でも使用した、アサインしたいヒトのユーザ名を。taskIdは、フォームのタスクオブジェクトがresultObjだったばあい CInt(resultObj.Id) と入れてください。実行すると、上記で説明したAPIをコールしてタスクをアサインします。
006.png

あ、TL;DR にも書きましたが、ワークフロー上からAPIを叩く場合は「Orchestrator への HTTP 要求」アクティビティを利用するのが簡単です。動いているロボットの権限で動作するので認証は不要(つまり User Key/Client Idを指定しなくていい) となり、アクティビティの入力項目はとってもシンプルになります。

そのほかのカスタムアクティビティ「Token」「User」も、上記で説明したAPIを内部でコールして access_token やユーザIDを取得するサンプルになっています。

ソースコード

ご興味がありましたらソースもありますのでどうぞ。

https://github.com/masatomix/kino.UiPath.OrchestratorAPI (ソース)
https://github.com/masatomix/kino.UiPath.OrchestratorAPI/releases (nupkgはココからでも。)

2019/12/16追記:
GitHubのマスターブランチはUser Key/Client Idを利用する方式からRobot認証をそのまま使う方式に変更しました。本記事バージョンのソースは https://github.com/masatomix/kino.UiPath.OrchestratorAPI/releases/tag/1.0.13 にあります。

カスタムアクティビティ開発するにあたって、

  • Visual Studioでホンキでつくる方式じゃなくて、UiPath Studioの「ライブラリ」機能でカスタムアクティビティは開発し、NuGetサーバにPublishした
  • Developer Community 第11回 でも説明があった「Swaggerからカスタムアクティビティを自動生成する機能」を使ってみた(銀の弾丸、ではなかった、、かなー)
  • 引数に注釈をつけることでプロパティに説明が表示されるようにした

などいくつかTIPSがありましたが、時間があったらあらためて記事にしようかと思います。。

ということで、おつかれさまでしたー。

この記事は RPA Advent Calendar 2019 の 12/13 の記事ですが

この記事は12/13に公開されますが、12/13はわたしも運営に関わっている UiPathのユーザコミュニティ「UiPath Friends」の年末イベント日です!
【第2回】UiPath Friends 東京 ~全員集合の年末大感謝祭!ライブ配信もやってみます!~
ご興味がある方は是非ともご参画くださいませーー。

関連リンク

  1. さらには$はURLエンコードしないのが正しいっぽいんだけど通るので気にしない:-)

15
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?