MuleSoft 入門(4)DataWeave によるデータ変換(2/2)

December 19, 2019 Minoru Nakanishi

こんにちは、アピリオの中西です。前半の MuleSoft 入門(4)DataWeaveによるデータ変換(1/2)では、DataWeave の構造と簡単な記法に関してご紹介しました。後半では、より実践的な DataWeave の変換例を紹介しようと思います。

DataWeave での変数の利用

DataWeave 2.0 は、変数が関数のように動作する関数型プログラミング言語です。 変数には値が割り当てられ、定数またはラムダ式で定義されます。

%dw 2.0 
output application/json 
var message = "Hello MuleSoft" // 定数による値の定義 
var toUpper = (str) -> upper(str) // ラムダ式による値の定義
var addSuffix = (msg, func, suffix) -> func(msg ++ suffix) //変数の引数に関数を定義
--- 
{ 
  message1 : message, // "Hello MuleSoft"
  message2 : toUpper(message), // "HELLO MULESOFT"
  message3 : addSuffix(message, toUpper, " DataWeave")  // HELLO MULESOFT DATAWEAVE 
}

[変数を利用した DataWeave 例]

ラムダ式変数は関数のように動作し、ラムダ式内で使用するパラメータを含めることもできます。

DataWeave 変数にはグローバルとローカルの2つの変数のスコープがあります。グローバル変数はヘッダーで初期化され、本文の任意の箇所から参照できます。先ほど [変数を利用した DataWeave 例] で紹介した

var message = "Hello MuleSoft"

など、var キーワードを用いて定義した変数がグローバル変数です。ローカル変数は using (<variable-name> = <expression>) という構文でスクリプトの本文中で初期化され、その変数を初期化したスクリプトのスコープ内からのみ名前で参照できます。

%dw 2.0 
output application/json 
--- 
userInfo: using (firstName = "アピリオ", lastName = "太郎") { // スコープはuserInfo内 
  person: using (user = firstName, gender = "man") { // スコープはperson内 
    name: user, // "アピリオ"
    gender: gender // "man"
  }
}

[ローカル変数を利用した DataWeave 例]

DataWeave での関数の利用

fun キーワードを使用して、DataWeave スクリプトのヘッダーまたは本文内で関数を宣言できます。ヘッダーで宣言した関数は、スクリプト本文の任意の場所で呼び出すことができます。

%dw 2.0 
output application/json 

// 関数 getType の宣言
fun getType (code: Number) = 
    if (code == 1) "Type A" 
    else "Type B"
--- 
{ 
  type: getType(1) // "Type A"
}

[関数を利用した DataWeave 例]

上記例では数値型の引数を1つ指定する必要のある関数を定義した例です。関数に定義された引数が2つの場合は、"関数(引数1, 引数2)" もしくは "引数1 関数 引数2" という2種類の記述方法があります。例えば、以下のような関数を定義します。

%dw 2.0 
output application/json 
fun combine(str1, str2) = str1 ++ str2
---
{
 "text": combine('Hello', 'World') // HelloWorld
}

これは "関数(引数1, 引数2)" の形式で関数を呼び出した例です。"引数1 関数 引数2" の形式で記述する場合は、

'Hello' combine 'World'

と記述します。引数が3つ以上の場合は、"関数(引数1, 引数2, 引数3)" という通常の呼び出し表記のみがサポートされます。

fun combine(str1, str2, str3) = str1 ++ str2 ++ str3

つまり、上記のような関数は

combine('Hello', 'World', '!')

という形式でしか呼び出せません。

MuleSoft が標準で提供する DataWeave 関数はモジュールにパッケージ化されています。Core 型のモジュール以外は、ヘッダーで import  キーワードを利用して使用するモジュールまたは関数をインポートできます。以下の例のように3種類のインポート方法があります。

%dw 2.0 
output application/json 
import dw::core::Strings   // 【Pattern1】 モジュール全体をインポート 
import capitalize from dw::core::Strings // 【Pattern2】 特定の関数をインポート 
import * from dw::core::Objects // 【Pattern3】 モジュール内の全ての関数をインポート 
---
{ 
  "camelize": Strings::camelize("customer_first_name"),  // 【Pattern1】 関数の利用にモジュールの宣言が必要
  "capitalize": capitalize("customer_first_name"), // 【Pattern2】 モジュールの宣言は不要
  "keySet": keySet({"key1":"A","key2":"B"}) // 【Pattern3】 モジュールの宣言は不要
}

[ DataWeave における関数のインポート例]

DataWeave の基本的な変換例

本章では、DataWeaveの変換例を何点かご紹介します。

Object to Object

例えば、次に示す(A)の構造の payload を(B)の構造に変換する場合を考えます。

// (A) 変換前の payload
{ 
  "lastname" : "アピリオ", 
  "firstname" : "太郎", 
  "email" : null, 
  "sex" : "1", 
  "birthday" : "19801011", 
  "tel": "03-1234-5678", 
  "age": 35, 
  "office": "青山4F" 
}
// (B) 変換後の payload
{ 
  "username" : "アピリオ太郎"
  "e-email" : "",
  "age" : "35", 
  "sex": "男性",
  "category": "middle", 
  "birthday" : "1980/10/11" 
}

この例では、Object データのフィールド名の変更やフィールドの追加/削除・値の変換などを行う必要があります。 DataWeave で変換を行う場合は、以下のように記述します。

%dw 2.0 
output application/json 

type dateFormat = Date { format: "yyyyMMdd"} 
type stringDateFormat = String { format: "yyyy/MM/dd"} 
--- 
{ 
  "username" : payload.lastname ++  payload.firstname,  // (1) 
  "e-email" : payload.email default "",  // (2)
  "age" : payload.age as String,  // (3) 
  "sex": if (payload.sex == '1') "男性" else "女性", // (4) 
  "category": if (payload.age < 20 ) "young" else if (payload.age <50) "middle" else "senior", // (5)
  "birthday" : (payload.birthday as dateFormat) as stringDateFormat  // (6)
}

[Object to Object の変換例]

上記の変換例では、各フィールドに対して何かしらの DataWeave の変換を行なっています。

(1)++ 関数を利用した、文字列の連結 

(2)値が null の場合に利用されるデフォルト値の指定

(3)Number 型 -> String 型 の変換。 型定義は "as <任意の型>" という形式で記述する

(4)if / else 構文による分岐

(5)if / else if 構文による複数の分岐

(6)日付のフォーマット

DataWeave を利用することで Object のフィールドの定義追加・変更、型定義の変更、表示のフォーマット、分岐処理などがシンプルな記述で行えます。

Array to Array

例えば、次に示す(A)の配列(Array)構造の payload を(B)の構造に変換する場合を考えます。

// (A) 変換前の payload
{ 
 "users": [ 
  { 
   "lastname" : "アピリオ", 
   "firstname" : "太郎",
   "age" : 30
  }, 
  { 
   "lastname" : "アピリオ", 
     "firstname" : "次郎",
   "age" : 28
  } 
 ] 
}
// (B) 変換後の payload
{ 
 "users": [ 
  { 
   "username" : "アピリオ太郎", 
   "age" : "30"
  }, 
  { 
   "username" : "アピリオ次郎", 
   "age" : "28"
  } 
 ] 
}

この例では配列に複数格納されている Object のフィールド定義と値を変換する必要があります。以下に DataWeave の実装例を記載します。

%dw 2.0 
output application/json 
---
"users": payload.users map { 
  "username" : $.lastname ++ $.firstname, 
  "age" : $.age as String
}

[map 関数を利用した DataWeave の変換例]

配列データの各値に対して変換処理を行う場合は、 map 関数を利用します。上記例は、

payload.users map(data, index) -> {
  "username" : data.lastname ++ data.firstname,
  "age" : data.age as String
} 

のようにラムダ式で記述することもできます。引数を指定しない場合は、$ で第一引数、 $$ で第二引数にアクセスすることができます。

フィルター / ソート

例えば、次に示す(A)の構造の payload を(B)の構造に変換する場合を考えます。

// (A) 変換前の payload
{ 
 "users": [ 
  { 
   "lastname" : "アピリオ", 
   "firstname" : "太郎",
   "age" : 30
  }, 
  { 
   "lastname" : "アピリオ", 
     "firstname" : "次郎",
   "age" : 28
  },
   {
     "lastname" : "アピリオ",
     "firstname" : "三郎",
     "age" : 25
   }
 ] 
}
// (B) 変換後の payload
{ 
 "users": [ 
  { 
   "username" : "アピリオ三郎", 
   "age" : 25
  }, 
  { 
   "username" : "アピリオ次郎", 
   "age" : 28
  } 
 ] 
}

この例では年齢が 30 歳以下のユーザを年齢の昇順に並べ換える処理を行います。以下に DataWeave の実装例を記載します。

%dw 2.0 
output application/json 
---
"users": payload.users
   filter($.age < 30)
   orderBy($.age)
   map(data, index) -> {
    "username": data.lastname ++ data.firstname,
    "age" : data.age
   }

[配列を操作する DataWeave の変換例]

Array to Array の例で紹介した map 関数のように、配列を操作する関数はいくつか標準で提供されています。今回の例では条件に一致するデータのみに絞り込む filter 関数、指定した項目でソートを行う orderBy 関数を利用しています。map 関数と同様にラムダ式で記述することもできます。SQL や Java の Stream API に馴染みのある方は実行結果をイメージしやすいのではないでしょうか。

ただし System API で Salesforce コネクタのクエリ実行やデータベースコネクタによるDB接続などを行う場合は、DataWeave よりもクエリで絞り込みやソートを行う方がパフォーマンスが期待できるので、実装時には注意してください。

dw::Mule モジュールの利用

DataWeave には、Mule Runtime Engine とやり取りする関数も提供されています。

・lookup 関数

[lookup 関数の利用例]

lookup 関数を使うことで、DataWeave から直接フローを呼び出すことができます。引数1 に 呼び出したいフロー名(SubFlowはサポートされていません)、引数2 に payload を指定します。オプションとして、引数3 にタイムアウトまでの時間を ms で指定することもできます。DataWeave だけで表現が難しい複雑なロジックや、既に定義されているフローのロジックが再利用できる場合に利用を検討します。

・p 関数

[p 関数の利用例]

p 関数は、システムプロパティ、または環境変数などの入力プロパティの値を識別する文字列を返します。通常、プロパティ値は yaml ファイルなどに記述し、 Configuration properties を利用して Mule アプリケーションの実装時に利用できるように設定します。上記例では、 global-properties.yaml 形式のファイルに定義したプロパティを DataWeave から呼び出しています。

 

いかがでしたでしょうか。Javaのような手続き型のプログラミング言語とはずいぶん書き方が異なるため、難しいと感じられた方も多いのではないでしょうか。Mule アプリケーションの実装を行う以上は  DataWeave の学習は避けては通れないと思いますが、DataWeave 自体はデータ変換に特化した言語なので慣れてしまえば API 実装効率が格段に向上すると思います。今回紹介した関数や記述例は、実際の API 実装時によく利用する代表的な変換例ですが、DataWeave には様々なモジュールおよび関数が標準で提供されています。詳細は MuleSoft 公式ドキュメント(DataWeave リファレンス)をご参照ください。

次回は Design CenterのFlow Designer を利用して Mule アプリケーションを開発する手順について解説します。

 

[MuleSoft入門シリーズ]

MuleSoft入門(1)MuleSoft による API-led なアプリケーションネットワーク

MuleSoft入門(2)ようこそ Anypoint Platform へ

MuleSoft入門(3)Anypoint Studio による API の実装

MuleSoft入門(4)DataWeave によるデータ変換

MuleSoft入門(5)Flow Designer で Mule アプリケーションを開発

MuleSoft入門(6)MUnit による単体テスト

MuleSoft入門(7)API 開発におけるテストの考え方

MuleSoft入門(8)ポリシーと SLA

MuleSoft入門(9)カスタムポリシーの開発

MuleSoft入門(10)Mule API のバージョン管理

MuleSoft入門(11)ランタイムログの自動アーカイブ

著者について

2018年にアピリオに入社し、Salesforce を中心としたクラウドの世界に足を踏み入れました。2019年には MuleSoft のプロジェクトに携わり、API 主導の開発に強い興味と関心を持っています。IT 技術の変遷が激しい今だからこそ、勉強に励んで自分の価値を高めようと絶賛奮闘中です。

Minoru Nakanishi のコンテンツをもっと見る
戻る
MuleSoft 入門(5)Flow Designer で Mule アプリケーションを開発
MuleSoft 入門(5)Flow Designer で Mule アプリケーションを開発

今回はクイックにAPIの開発を行いたいユーザー向けに、Design Centerが提供する Flow Designer を使ったブラウザ環境でのMuleアプリケーションの開発についてご紹介します。Flow Desi...

次へ
MuleSoft 入門(4)DataWeave によるデータ変換(1/2)
MuleSoft 入門(4)DataWeave によるデータ変換(1/2)

今回は、Mule アプリケーションを介して受け取ったデータ( payload, attributes, variables など)にアクセスし、変換するための独自の MuleSoft 式言語である DataWeav...

アピリオまでお気軽にお問合せください

ご質問はこちら