足立区在住SEのブログ

足立区在住のSEが主にシステム開発について書いています。

OutSystemsでAWS S3を操作する。

外部システムとのファイル連携でAWSのS3を使っているため、OutSystemsからS3を操作しています。
FORGEからインストールをした「AdvancedAmazonS3」モジュールを使っています。

f:id:adachinose:20170627214551j:plain

「AdvancedAmazonS3」には、S3FileとAmazonTokenというStructureが用意されているので
そこに必要なパラメータをセットします。

S3File
  Bucket=バケット名
  SubFolder=サブフォルダ名
  Key=ファイル名

AmazonToken
  AccessKey=アクセスキー
  SecretKey=シークレットアクセスキー

上記をセットしてFetchFileを呼び出すと
戻り値のS3File.Contentでファイルのバイナリーデータを取得できました。

パラメータのS3File.ContentにバイナリデータをセットしてSaveFileを呼び出すと
S3にファイルを保存することができました。


できてしまうととても簡単なのですが
これを作っていて引っかかったのが、パラメータ「Key」の指定の仕方でした。

AWS Tools for Windows PowerShell」でS3を操作するときは

Write-S3Object -BucketName "BucketName" -File "c:\temp\test.txt" -Key "/SubFolder/FileName"

のような感じで、Keyにサブフォルダ名とファイル名を一緒に渡せたのですが

「AdvancedAmazonS3」では一緒に渡すとNGで、分けて渡す必要がありました。

× Key="/SubFolder/FileName"

○ SubFolder="SubFolder"(※末尾にスラッシュを付けない)
  Key="FileName"

この渡し方が書いてあるドキュメントを見つけられず
パラメータの渡し方をいろいろ試してやっとのことでS3にアクセスできました。

あと、FetchFileを呼んで指定したファイルがないとExceptionが発生してErrorログが出るため
ファイルの存在チェックのたびにErrorログが出てしまい、存在チェックをあきらめました。
Errorログを出さないようにする方法がわかればよかったのですが。。

OutSystemsのSOAP APIを試してみる。

現在、開発中のシステムでSOAPで連携するシステムがあり
SOAP APIも試しています。

REST APIと同じような手順で簡単にAPIコールの処理を実装できます。

Consume SOAP APIを新規作成すると連携先のWSDLのURLを入力を求められる。
f:id:adachinose:20170619101646j:plain

SOAP APIが追加される。
f:id:adachinose:20170619095914j:plain

RequestとResponseのXMLに対応するStructureも作成される。
f:id:adachinose:20170619095933j:plain


アクションは簡単に作れたのですが
コールしてみるとXMLのフォーマットが合わないのか
エラーが出てなかなか動きませんでした。
標準機能だと動きが見えないのでデバッグが難しいです。

ForgeのWebServiceProxyをインストールすると
SOAPの送受信内容を取得できるようだったので入れてみました。
(前提モジュールとしてardoHTTPが必要のようです。)
f:id:adachinose:20170619100038j:plain

APIコールの前後で
実行前にTrace_setCommit
実行後にTrace_Get
を呼び、パラメータを手探りで入れて何度か試すと
RequestとResponseの値を取得できました。
本来、なんの値を入れるのが正しいのかはよくわかっていません。。。


今回呼び出そうとしているAPIでは、Headerにパラメータをセットする必要があり
ExtentionのEnhancedWebReferencesの
SetWebReferenceSoapHeadersを使いました。
f:id:adachinose:20170619100619j:plain

これでHeaderに指定の要素を追加してリクエストを送ることができました。


SOAPJSONに比べて敷居が高いように感じます。
処理がブラックボックスになっていて、上手くいかないときに調べられるポイントが少なく
ドキュメントも少ないので、いろいろやってみたらなんとなく動いたという感じです。
今どき、SOAPには力を入れていないのかもしれません。

OutSystemsでSendGrid API v3をコールする。

SendGrid の WEB API v3 を試してみました。
JSONでリクエストを投げるだけでメール送信ができます。

Documentation画面からJSONを入力して簡単にテスト送信できます。
https://sendgrid.com/docs/API_Reference/api_v3.html
f:id:adachinose:20170615112824j:plain

1.HeadersのAuthorizationに
 「Bearer {API_KEY}」を入力。
({API_KEY}は、SendGridにログインしてSetting>API Keys から作成するキー)

2.Request Bodyに、下のサンプルのJSONが入っているので宛先などを修正して
「SEND REQUEST」をクリックするだけでメールが送れます。

{
  "personalizations": [
    {
      "to": [
        {
          "email": "john.doe@example.com",
          "name": "John Doe"
        }
      ],
      "subject": "Hello, World!"
    }
  ],
  "from": {
    "email": "sam.smith@example.com",
    "name": "Sam Smith"
  },
  "reply_to": {
    "email": "sam.smith@example.com",
    "name": "Sam Smith"
  },
  "subject": "Hello, World!",
  "content": [
    {
      "type": "text/html",
      "value": "<html><p>Hello, world!</p></html>"
    }
  ]
}


Transactional Templatesで用意したメールテンプレートの文面を使って
メールを送ることもできます。
template_idでテンプレートを指定して、substitutionsで置換文字列を渡します。

{
  "personalizations": [
    {
      "to": [
        {
          "email": "john.doe@example.com"
        }
      ],
      "substitutions": {
        "-name1-": "john",
        "-name2-": "doe"
      }
    }
  ],
  "from": {
    "email": "sam.smith@example.com"
  },
  "template_id": "{Transactional Templatesのキー}"
}


メールテンプレート
f:id:adachinose:20170615113609j:plain


こんな風に置換されたメールが送信されます。

john
doe

~本文~


このAPIをコールする処理をOutSystemsで作ってみました。

1.Consume REST APIを新規作成して、「Body」タブにJSONを貼り付ける。
f:id:adachinose:20170615114047j:plain

2.「Headers / Auth」タブで、
Authorization(API_KEYを指定する)と
Content-Type("application/json"を指定)を追加する。
f:id:adachinose:20170615114112j:plain


RESTの下に、Sendgrid/PostSendが作成されます。
f:id:adachinose:20170615114123j:plain


JSONに対応するStructureも自動で作成されます。
f:id:adachinose:20170615114134j:plain


SendGridのAPIはResponseのBodyが空で返ってくるようで
HTTPステータスコードで結果を取得するのですが
OutSystemsのREST APIを普通に実行するだけだと
ステータスコードを取れないようです。

REST APIの「On After Response」プロパティを設定し
下記のようにOnAfterResponseを用意して
その中でステータスコードをsession Variablesにセットして取得する必要があるようです。
f:id:adachinose:20170615114148j:plain

OutSystemsのプロセス機能

OutSystemsの特徴としてプロセス機能があります。
複数の処理をフローチャートでつなげて、業務の一連の流れに合わせて処理します。
いわゆるBPMツールと同じような機能のようです。

f:id:adachinose:20170612175235j:plain

例えば、販売管理システムであれば

 引合→与信→受注→出荷→請求→入金

のような業務の流れをフローチャートで定義できます。

上記のような販売管理はプロセスを使わなくても実現できると思いますが
プロセスを使うと

・特定の条件を満たすまで待機して、条件をトリガーに非同期で処理を実行する。
(決裁が下りるまでは仮受注で、決裁されると在庫引き当て処理を実行する)

・複数の条件を満たすことをトリガーに処理を実行する。
(順不同の上長決済と経理決済の両方が揃うと、在庫引き当て処理を実行する)

・条件によって実行する処理を切り替える。
(決裁されたときに、在庫があれば在庫引き当て、なければ発注処理を実行する)

といった処理をフローチャートの定義で実装できます。

 何かの条件を満たすことをトリガーに非同期で処理を実行するというのは
素で実装すると結構しんどいですし
後から処理の順序や条件、分岐を変えるとなると非常に大変ですが
OutSystemsでは、フローチャートを書き換えるだけで比較的簡単に実装できます。

また特定のプロセスが、今、一連の処理のどの段階にいるかを
フローチャート形式の図で見ることができるのもすごいです。

 

1.現在、実行中のプロセスの件数をタイプ別に表示

f:id:adachinose:20170612180501j:plain

2.タイプを選択するとプロセスの一覧を表示

f:id:adachinose:20170612180529j:plain

3.プロセスを選択すると、このプロセスの状況をフローチャートで表示。

(実行済みの処理は色付きで表示される。)

f:id:adachinose:20170612180537j:plain


プロセス機能を使うと使わないとでは、OutSystemsの威力が大きく変わると思います。

OutSystems開発で不便な点(参照渡し、継承、ブランチ)

非常に完成度の高いOutSystemsですが
OutSystems(.Net版)で開発をしていて、不便な点もいくつかあります。

1.引数の参照渡しができない

関数に引数の参照渡しができないので、関数の中で加工した値を取得するには
必ず戻り値で受け取る必要があります。
ObjectやListに複数の関数で値をセットするような処理が書きにくいです。

2.継承、インターフェースが使えない。

継承が使えないので、処理の共通化がうまくできず
同じ処理を何度も書かないといけないケースがありました。
例えば、各EntityにDB更新時刻と更新者のカラムを用意し
共通の更新処理で必ず値を入れるといったよくある処理を書くのに
共通処理をスーパークラスで実装したり
DB更新時刻と更新者をインタフェースで定義する
といったことができないのが不便です。
このせいで、ソースのメンテナンス性が低下しています。

3.バージョン管理でブランチの管理ができない

OutSystemsでは標準でソースのバージョン管理の仕組みが用意されていて
便利なのですが、Gitのようにブランチを切ることができないので
システム稼働後に新機能開発と不具合修正を並行して行うのに苦労しています。

 

4.ソースの一覧性が低い

これは慣れの問題も大きいですが、フローチャート形式でプログラムを組むのは
ぱっと見てイメージし易い反面、一覧性に劣ると思います。
とくに多数の項目を代入した場合に、アイコンを開かないと代入式を見られないので
修正時やデバッグ時に、どこを直せばいいのか確認するのが大変です。
(一応、Assignのアイコンにカーソルを当てると代入式の一覧がポップアップで表示されるが
カーソルをはずすと消えてしまうし、コピペもできない。)

また、分岐の矢印が結構間違えやすく、よくTrueとFalseを逆にして不具合になっています。
ソースコード
if {} else {}
と書いてあった方が、直感的に見てわかりやすい気がします。

OutSystemsのDBの主キー

OutSystemsのEntityの主キーは複合キーにできず、単一カラムを主キーにする必要があります。
また、主キーは数値型だと自動採番できるので、数値型が推奨されているようです。

これまでの経験上、複合キーを使うことが多かったのではじめはとまどいましたが
今のところ、複合キーを使えないことによる問題は起きていません。

例えば商品マスタでは、他システムでは商品コードと会社コードの複合キーになっており
OutSystemsのシステムでも、その組み合わせで論理的に一意になるのですが
物理的には単一の数値型の主キーと持ち、商品コードと会社コードにユニークキー制約をつけています。
SQLでの結合は商品コードと会社コードを使うことで特に問題なく使えています。

OutSystems上のEntityであれば、上のように単一の主キーを持たせることができますが
既存のテーブルを使うときは当然主キーを変えられません。
その場合は、OutSystems上では主キーがないテーブルとして扱われ
OutSystemsで用意されているDB更新用のメソッドが使えません。
代わりにAdvancedSQLで更新SQLをほぼベタで書くことになるので
これは生産性が落ちてしまうと思います。

OutSystemsはアプリケーションとDBが連動するのが基本の作りになっているようなので
既存DBを参照しての開発はあまり得意ではないように見えます。
新規DBを作るか、既存DBを使うかは、OutSystemsで開発をするかどうかの
大きな判断基準になると思います。

OutSystemsでのDB操作

OutsystemsではEntityを定義すると、OutSystemsが物理DBに直接変更を加え
OutsystemsのEntity定義と同期する物理テーブルを作成、変更します。
そのため、開発者がDBを操作しなくても簡単にテーブルやカラムの追加を行うことができます。


通常であれば、
DDLを書いてDBに変更を加え→アプリケーションのDB操作処理を修正(Entityに対応するDAOの修正など)

とするところを、ServiceStudio上でEntityに項目を追加するだけでよい。
よくDBの変更時に、アプリとDBの同期が取れずにエラーとなることがあるが
OutSystemsが整合性を保ってくれるので、システム稼働中でも安心してカラムの追加ができます。

DBの定義が固まりきらないまま開発に着手しても
必要に応じて簡単にDBを変更できるので、アジャイルのような進め方では
大きく生産性が上がると思います。
今回、私がやっている開発もまさにそうでした。


OutsystemsがDBを直接変更することのデメリットとしては
・物理テーブル名を自分で操作できないので、外部システムからの参照が困難。
・Entityの項目を変更、削除した場合に、物理DBにはもとのカラムが残ってしまう。
直接DBを参照したときに不要なカラムがあってわかりにくい。

といったことが生じています。
実際に、開発、運用するにあたっては、DBを直で参照する必要もあるので
その点は少し不便も感じています。
が、ビューを作るなどの回避策もあるので大きな問題にはなっていません。
アプリとDBが自動で同期されるのは、とても良いと思います。