ServiceNowで外部システムとファイルを送受信する方法

検討・企画

ServiceNowは、多くの外部システムと連携し、自動化されたワークフローを構築することが可能です。この記事では、外部システムと画像やPDFなどのバイナリファイルを送受信する方法を解説します。

結論

外部システムとのファイルの送受信は、通信の起点、データの所在、送受信時のデータ形式に応じて様々なパターンが存在します。各パターンごとの実現方法を下表に示します。

方式データ形式実現方法
ServiceNowから外部システムにファイルを送信する場合
通信の起点:ServiceNow
ファイルの場所:ServiceNow
バイナリ・REST Step
・REST Message
Base64エンコード・Base64エンコードした上でREST Step or REST Message
multipart/form-data形式・REST Step
ServiceNowから外部システムのファイルを取得する場合
通信の起点:ServiceNow
ファイルの場所:外部システム
バイナリ・REST Step
・REST Message
Base64エンコード・REST Step or REST Messageで受信した上でGlideSysAttachmentでファイルを保存
multipart/form-data形式– (送信のための方式なので考慮不要)
外部システムからServiceNowのファイルを取得する場合
通信の起点:ServiceNow
ファイルの場所:外部システム
バイナリ・Attachment APIのGET /now/attachmentを利用
Base64エンコード・カスタムAPIを利用
multipart/form-data形式– (送信のための方式なので考慮不要)
外部システムからServiceNowにファイルを送信する場合
通信の起点:外部システム
ファイルの場所:外部システム
バイナリ・Attachment API
・Import Set API
Base64エンコード・カスタムAPIを利用
multipart/form-data形式・Attachment API
・/sys_importset.do
ServiceNowにおける外部システムとのバイナリファイルの送受信方法のまとめ

以下、各パターンにおける具体的なデータの送受信方法について解説します。

前提知識

まず、ServiceNowと外部システム間でファイルをやり取りするために必要な基本的な知識について解説します。

Webシステムにおける画像やPDFなどのバイナリファイルの送受信方法

ServiceNowはWebシステムの一つであるため、まずはWebシステム全般における画像やPDFなどのバイナリファイルを送受信する一般的な方法について説明します。

Webシステム間でHTTP(S)を利用してバイナリファイルをやり取りする際には、主に以下の3つの方法が一般的に使われます。ServiceNowもこれらの方式をサポートしています。

  • バイナリをそのまま送受信
    リクエストボディにバイナリデータを直接設定するシンプルな方法です。
  • Base64エンコードを使用して送受信
    バイナリデータをBase64という方式でテキストに変換して送受信する方法です。この方法ではデータサイズが増えるデメリットがありますが、JSON形式のデータの中に画像などを含めることができるため、多くのAPIで使用されています。
  • multipart/form-data形式で送受信
    フォームデータを送信する際に使われる方式で、複数のテキストやファイルを同時に送信できます。リクエストボディを区切り文字で複数の部分に区切ってテキストやファイルを指定するため、multipartと呼ばれます。ファイルを含める場合は、バイナリデータはエンコードされず、そのまま送信されるのが一般的です。

なお、システム間でファイルを転送する際にはFTP(SFTP)も利用されることがあります。ServiceNowでは、MIDサーバやRPAの機能を用いてローカルシステムとファイルをやり取りする際にFTP(SFTP)を利用することもできますが、本記事では対象外とします。

ServiceNowにおいて外部システムと通信する方法

ServiceNowでは、外部システムとの通信を行うために、いくつもの方法が用意されています。ここでは、それらのうち主要な方法について解説します。

ServiceNowが通信の起点となる場合:REST Step or REST Message

ServiceNowから外部システムにリクエストを送る場合、主にFlow(ワークフロー機能)の中で使用するREST step、もしくはスクリプトから直接呼び出すREST Messageを利用します。

方式概要備考
REST stepノーコードで外部システムとのシステム連携を構築するための機能・Flowの一部として組み込むことで、簡単に外部連携が構築可能
・使用にはIntegration Hubのライセンスが必要(トランザクション単位の課金)*1
REST Messageスクリプトを使用して外部システムと連携する機能・コーディングが必要で、開発の難易度が高い
・ServiceNow標準の機能であり、トランザクション単位の課金は発生しない
ServiceNowが通信の起点となる場合の外部連携方法

*1 課金体系については2024年Xanaduバージョン現在のものです。今後変更される可能性があるため注意してください。

外部システムが通信の起点となる場合:標準公開API or カスタムAPI

外部システムが通信の起点となる場合、ServiceNowでは標準で提供されているAPIか、カスタムAPIを利用して通信を行います。

方式概要備考
標準公開されているWeb APIServiceNowが標準で提供する外部公開API・システムアカウントを発行するだけで利用可能で、開発作業は不要
カスタムAPIスクリプトを使って独自のAPIを作成し、外部システムに公開する・スクリプト作成が必要で開発の難易度が高い
・自由度が高く、柔軟な実装が可能
外部システムが通信の起点となる場合の外部連携方法

IP制限がかかったネットワーク内に外部システムが存在する場合はMID Serverを介して通信

外部システムが通信の起点となる場合は基本的には問題ありませんが、ServiceNowが通信の起点となる場合は、外部システムがIPアドレス制限などの通信制限を行っているケースがあります。ServiceNowインスタンスから直接アクセスできない内部ネットワークに外部システムが存在する場合はMID Serverを介して通信を行う必要があります。詳細については、次の記事を参照ください。

ServiceNowにおけるファイルの保管方法

ServiceNowにはGoogleドライブ・Oneドライブ・Boxのようなファイルスを単体で格納するためのトレージは存在せず、ファイルは特定のレコードに対する添付ファイルとして保存されます。GUI上でも、ストレージのような場所にファイルをアップロードするのではなく、「特定のレコードに添付する」という形でファイルをアップロードします。

データベース上では以下の2つのテーブルに分けて格納されます。

  1. Attachment(添付ファイル) [sys_attachment]
    ファイル名、サイズ、拡張子といったメタデータを保管します。
  2. Attachment Document(添付ドキュメント) [sys_attachment_doc]
    ファイルの実体そのものを保存します。ファイルサイズが大きい場合は、1つの添付ファイルが複数のレコードに分割されて保存されます。

ファイルをスクリプトから操作する際はGlideSysAttachmentを使用

上述のように、添付ファイルは複数のテーブルにまたがって、かつ必要に応じて分割して保管されているため、スクリプトから操作する際には、Attachment(添付ファイル)を操作するためのAPI(クラス)であるGlideSysAttachmentを利用します。このAPIを利用することで、ファイルの取得や作成が可能です。

ここまでが前提知識です。以降はパターンごとの外部システムとの添付ファイルの送受信方法について解説します。

ServiceNowから外部システムにファイルを送信する場合

バイナリ

REST step、またはREST Messageを用いてバイナリを直接外部システムに送信することができます。

REST stepを用いる方法

REST stepの設定において、HTTP Methodを”POST”に、Request Typeを”Binary”を選択すると、指定したAttachment(添付ファイル)レコードのバイナリデータをリクエストボディに設定することができます

図では簡単のためAttachmentレコードを直接指定しましたが、一般的には事前に”Get Attachments on Record”アクションなどで取得したAttachmentのSysIDを渡すことになります。

REST Messageを用いる方法

RESTMessageV2.setRequestBodyFromAttachment()を用いることで、指定したAttachment(添付ファイル)レコードのバイナリデータをリクエストボディに設定することができます。使い方はシンプルで、AttachmentレコードのSysIDを引数に渡すだけです。

var request = new sn_ws.RESTMessageV2();
// requestのエンドポイント、メソッド、ヘッダ等を設定
request.setRequestBodyFromAttachment('<attachment sys_id>');
response = request.execute();

Base64エンコード

Base64エンコードしたファイルを送信する必要がある場合は、事前にスクリプトでファイルをBase64エンコードした文字列を取得した上で、REST stepやREST Messageに渡します。ただし、Base64エンコードしたファイルの取得方法はスクリプトをScopedで書く場合とGlobalで書く場合で異なる点に注意が必要です。

ScopedでBase64エンコード済みファイルを取得する方法

Scopedの場合は比較的シンプルで、GlideSysAttachment.getContentBase64()を使ってBase64エンコードされたファイルを取得できます。以下に、指定されたインシデントレコードに添付されたファイルをBase64形式で取得し、JSON形式のペイロードを作成するコード例を示します。

var incidentSysID = 'インシデントレコードのSysID';
var gsa = new GlideSysAttachment();
var attachments = gsa.getAttachments('incident', incidentSysID); // Get attached file(s)
var payload = [];

while (attachments.next()) {
    var fileName = attachments.getValue('file_name'); // Get file name of attachment
    var attachmentContent = gsa.getContentBase64(attachments); // Get attachment content in Base64
    
    payload.push({
        'filename': fileName,
        'contentBase64': attachmentContent
    });
}

gs.info(JSON.stringify(payload));

GlobalでBase64エンコード済みファイルを取得する方法

Globalでは、GlideSysAttachment.getContentBase64()が利用できず、”undefined”を返してしまいます。そのため、Scopedで作成したScript Includeを介して取得することを推奨します。

なお、Community等で調べると、次のようにGlideSysAttachment.getBytes()とGlideStringUtil.base64Encode()を使用してGlobalでBase64エンコード済みファイルを取得する方法が紹介されていますが、これらは公式にドキュメント化されていないAPIであるため、基本的には使用しない方がよいでしょう。

var incidentSysID = 'インシデントレコードのSysID';
var gsa = new GlideSysAttachment();
var attachments = gsa.getAttachments('incident', incidentSysID); //create attachment GlideRecord
var payload = [];

while (attachments.next()) {
    var fileName = attachments.getValue('file_name'); // Get file name of attachment
    var attachmentContent = GlideStringUtil.base64Encode(gsa.getBytes(attachments)); // Encode attachment content in Base64
    
    payload.push({
        'filename': fileName,
        'contentBase64': attachmentContent
    });
}

gs.info(JSON.stringify(payload));

multipart/form-data形式

multipart/form-data形式でファイルを送信する場合、REST stepを使用します。REST stepにおいて、HTTP Methodを”POST”に、Request Typeを”Multipart”を選択すると、Multipartを構成するUIが表示されます。このUIで(+)ボタンを押してPart Typeを”File”とすることで、ファイルを添付して送信することができます。

一方で、REST Messageではmultipart/form-data形式のリクエストを作成するためのメソッドが存在せず、次の理由から恐らく実現は困難です

  1. バイナリデータの扱いが困難
    REST Messageでは、ペイロードにバイナリデータを直接含める必要がありますが、ServiceNowではスクリプト内でバイナリデータを直接扱う、公式にドキュメント化されたAPI(クラス)が存在しません。
  2. リクエストボディの型の制約
    仮にペイロードを作成できたとしても、RESTMessageV2.setRequestBody()はString型しか受け付けません。

実現方法をご存じの方がいれば、コメントでご教示いただければと思います。

ServiceNowから外部システムの中のファイルを取得しに行く場合

バイナリ

REST stepまたはREST Messageを用いて、外部システムのファイルをバイナリで返すAPIやファイルをダウンロードするエンドポイントにアクセスし、その結果であるファイルをAttachmentテーブルに格納することができます

REST stepを用いる方法

REST stepの設定において、Save As Attachmentにチェックを入れた上で、ファイルを添付するレコードを指定します。

REST Messageを用いる方法

RESTMessageV2.saveResponseBodyAsAttachment()を用いることで、レスポンスのバイナリデータを指定したレコードの添付ファイルとして保存することができます。

コード例は以下の通りです。レスポンスのオブジェクトに対してこのメソッドを呼び出すのではなく、リクエストを行うRESTMessageV2インスタンスに対してこのメソッドを呼び出した上でリクエストのを行う(execute()メソッドを呼ぶ)ことに注意です。

var request = new sn_ws.RESTMessageV2();
// requestのエンドポイント、メソッド、ヘッダ等を設定
request.saveResponseBodyAsAttachment(tablename, recordSysId, filename);        
response = request.execute();     

Base64エンコード

外部システムからBase64エンコードされたバイナリファイルが返ってくる場合は、レスポンスボディからBase64エンコード済みのファイル部分を取り出した上でスクリプトを用いて保存します。

Base64エンコード済みのファイルの保存取得方法はがスクリプトをScopedで書く場合とGlobalで書く場合で異なる点に注意が必要です。

ScopedでBase64エンコード済みファイルを保存する方法

Scopedの場合は、GlideSysAttachment.writeBase64()を用いることでBase64エンコード済みファイルをAttachmentテーブルに保存することができます。て保存します。

例として、ファイル名、ファイルタイプ、Base64エンコード済みのファイルの中身を含むペイロードが取得できた前提で、そのファイルを指定されたインシデントレコードに添付するコードを示します。

var incidentSysID = 'インシデントレコードのSysID';
var incident = new GlideRecord('incident');
incident.get(incidentSysID);

var gsa = new GlideSysAttachment();

var payload = { // このような形式のpayloadが取得できていると仮定
    'fileName': 'example.png',
    'contentType': 'image/png',
    'contentBase64': 'iVBORw0KGgoAAAANSUhEUgAA...==' // Example Base64 encoded content
};

// Write the Base64 encoded content as an attachment
var attachmentSysID = gsa.writeBase64(incident, payload.fileName, payload.contentType, payload.contentBase64);

gs.info('The attachment sys_id is: ' + attachmentSysID);

GlobalでBase64エンコード済みファイルを保存する方法

GlobalではwriteBase64()が利用できず、またドキュメント化されたメソッドも無いため、ScopedなScript Includeを介して実現します。

簡単にできる方法をご存じの方がいたらコメントをください。

外部システムからServiceNowの添付ファイルを取得する場合

バイナリ

外部システムからServiceNowの添付ファイルをバイナリで取得する場合は、標準で外部公開されているAttachment APIを利用します。

添付ファイルの取得:GET /now/attachment/{sys_id}/file

エンドポイント”GET /now/attachment/{sys_id}/file”を用いることで、添付ファイルをバイナリファイルとして取得することができます

curlコマンドの例を示します。

curl "https://<インスタンス名>.service-now.com/api/now/attachment/<AttachmentレコードののSysID>/file" \
 -u <認証情報> \
 -o "test.png"

このエンドポイントではAttachmenレコードのSysIDが必要となりますが、多くのユースケースでは、番号やSysIDが分かっているレコードから、そのレコードに添付されたファイルを取得します。そのため、次のエンドポイントとセットで利用されることが多いです。

メタデータの取得・検索:GET /now/attachment

“GET /now/attachment”を利用することで、Attachmentテーブルに格納されている添付ファイルのメタデータ(SysID、ファイル名、ファイルの種類、添付先のレコードなど)の一覧を取得することができます。

多くの場合、URLクエリパラメータ”sysparm_query”を利用してレコードのSysIDからそのレコードに添付されたファイルを検索するために利用します。

例として、インシデントレコードに添付されているファイルのメタデータを取得するcurlコマンドを示します。

curl "https://<インスタンス名>.service-now.com/api/now/attachment?sysparm_query=table_name%3Dincident%5Etable_sys_id%3D<インシデントレコードのSysID>" \
 -u <認証情報>

Base64エンコード

ServiceNowからBase64エンコードされたファイルを取得するための標準APIは提供されていません。そのため、外部システム側でBase64エンコードを行うか、Scripted REST API等を用いてエンドポイントを作成する必要があります。

エンドポイントを自作する場合は、上述のScopedでBase64エンコード済みファイルを取得する方法及びGlobalでBase64エンコード済みファイルを取得する方法を参照ください。

外部システムからServiceNowにファイルを送信(アップロード)する場合

バイナリ

外部システムからServiceNowにバイナリファイルを直接アップロードする場合に利用できるのが、Attachment APIのエンドポイント”POST /now/attachment/file”です。クエリパラメータでファイル名、添付先テーブル、添付先レコードのSysIDを指定し、リクエストボディにバイト列を書き込みます。

インシデントレコードにファイルを添付するcurlコマンドの例を示します。

curl -X POST "https://<インスタンス名>.service-now.com/api/now/attachment/file?file_name=<ファイル名>&table_name=incident&table_sys_id=<インシデントレコードのSysID>" \
 -u <認証情報> \
 -H "Content-Type: image/png" \
 --data-binary @test.png

Base64エンコード

外部システムからServiceNowにBase64エンコード済みのファイルを直接アップロードできる標準APIは提供されていません。そのため、外部システム側でバイナリ変換を行うか、Scripted REST API等を用いてBase64エンコード済みファイルを受け付けることができるエンドポイントを作成する必要があります。

エンドポイントを自作する場合は、上述のScopedでBase64エンコード済みファイルを保存する方法を参照ください。

multipart/form-data形式

外部システムからServiceNowにmultipart/form-data形式でファイルをアップロードする方法は、用途に応じて複数そんざいします。

Attachment API – POST /now/attachment/upload

汎用的に利用できるのが、Attachment APIのエンドポイント”POST /now/attachment/upload”です。

curlコマンドの例を示します。バイナリを直接送信する/fileとは異なり、ファイル名や添付対象レコードの情報は、マルチパートデータ内に含めます。

curl -X POST "https://<インスタンス名>.service-now.com/api/now/attachment/upload" \
 -u <認証情報> \
 -H "Content-Type: multipart/form-data" \
 -F "table_name=incident" \
 -F "table_sys_id=<インシデントレコードのSysID>" \
 -F "file=@test.png"

なお、ファイルを表すパートの名前の指定は無いようです。また、ファイルを複数添付しても初めの一つしかアップロードされませんでした。そのため、恐らく最初にアップロードされたバイナリのインプットを添付ファイルとして認識する仕様になっているようです。

Import Setを用いてExcelやCSVファイルを取り込ませたい場合は /sys_importset.do

従業員データの取り込みなど、ExcelやCSV形式のファイルを特定のテーブルにImport Setを経由して取り込ませたい場合はエンドポイント”/sys_importset.do”を利用します。

例として、Import Set “Sys UI Message”とTrasnform Map “Sys UI Message Transform Map”を用いて、Messageテーブルの翻訳をインポートするcurlコマンドを示します。

curl -X POST "https://<インスタンス名>.service-now.com/sys_import.do?sysparm_import_set_tablename=u_sys_ui_message&sysparm_transform_after_load=true" \
 -u <認証情報> \
 -H "Content-Type: multipart/form-data" \
 -F "file=@sysuimessagedata.xlsx"

sysparm_transform_after_load=trueとすることで、ファイルがアップロード後にTransform Mapを用いたデータの登録までを1回のリクエストで行うことができます。

このAPIは、XMLやJSON形式に変換してデータを送信する必要のあるImport Set APIと比べ使い勝手が良い反面、エラーハンドリングが不十分であることに注意が必要です。例えば、以下のような状況でも、200 – OKというステータスが返ります。

  • 存在しないImport Set名を指定した場合
  • 誤ったファイル形式(例: 画像ファイル)を送信した場合

また、成功した場合でも、リクエストボディは空で成否判定もできません。そのため、Transform Mapのログを定期的に確認するなど、エラーハンドリングや結果確認を補完する処理とセットで利用することを推奨します。

以上です。

コメント

タイトルとURLをコピーしました