# 3/22 MCD Exam Readiness ワークショップ
###### tags: `MuleSoftTraining`
- [MuleSoft Exam Readiness Kit - 認定資格試験への準備キット -](https://salesforce.quip.com/JBhRAIbXU9VO)
- 試験の予約方法や、当日の流れなど、試験準備に関して必要な情報はこちらにて!
- [MCD データシート](https://training.mulesoft.com/oltpublish/cmsres/downloads/MCD_level1_datasheet_japanese.pdf) で出題範囲を確認
- [MCD 模擬試験](https://training.mulesoft.com/course/development-fundamentals-mule4/quiz-diy-japanese) で実際の試験時間・問題数・難易度に近い問題を解いてみる
- 少し古い試験範囲から、模擬試験に出題されている場合もあります
# 1. アプリケーションネットワークの構築 (開発:基礎モジュール1, モジュール2)
## Q1: 実装とインターフェース
インターフェースに変更がない=API クライアントには変更が必要ない
※ユニットテストがあることによって、この実装の変更が起こしうる、APIクライアントへの影響をテストできる

ある日突然「コンセント」のインターフェースが変わったら...

## :star: API-led Connectivity (API主導の接続性)
- Experience API(EAPI)
- API クライアント毎の違いを吸収する(データ型、フォーマット, セキュリティ..)
- Process API(PAPI)
- ビジネスロジック、連携、統合、オーケストレーション
- System API(SAPI)
- バックエンドのデータを取得・更新・作成
- 統一のデータ型への変換を行うことも(SAP Customer <-> SFDC Customer)
## Spec-Driven Development (仕様駆動型開発)
- どちらのツール、どちらの言語でもOK!
- RAML 0.8/1.0 > *今回の試験では**RAML**が出題!*
- OAS 2.0(a.k.a Swagger)/3.0
- (AsyncAPI)
- なぜ?
- その API の役割や機能について合意をとる
- フィードバックをもらって改善する
- データ型、エンドポイント名、フィールド名、パラメータ (必須 or not)、などについての事前確認
- 仕様通りのバリデーションを自動で適用
- Studio にインポートして、土台となるスケルトン (インタフェースフロー)を自動で生成する
- Exchange に公開したタイミングで
- API ポータルが自動生成される
- 仕様をもとにドキュメントが自動生成されます
- API コンソールが自動生成される
- コネクタの自動生成 (REST Connect)
- モッキングサービスが自動生成される (プロトタイプ)
- [シミュレーションヘッダー](https://docs.mulesoft.com/jp/design-center/apid-behavioral-headers)機能で、より実際に近いモック呼び出しが可能(MS2-Delay etc..)

## C4E (Center for Enablement)
Anypoint Platform をより活用し、アセット(資産)の **再利用** を促進するための機能横断チーム・組織づくり
# 2. API の設計 (開発:基礎モジュール3)
## 「XXX の適切な呼び出し方は...?」系の問題では以下の3つを確認する
- 1. 何をしたいのか (HTTPメソッド、 CRUD)
- **GET** (記事のデータを*取得*する)
- PUT(完全に置き換える・更新する)
- PATCH(一部を置き換える・更新する)
- POST
- DELETE
- 2. フォーマット(形式)
- **XML**, JSON..
- 3. 必須 (required) のパラメータ
- クエリパラメータ
- URI パラメータ
- ヘッダー
※RAML では "?" や `required: false` に設定しなければ、パラメータはデフォルトで必須となる
## REST API を設計するための言語 (ツール)
- **RAML** 0.8 / **1.0** < MCD ではこちらが重要!
- https://raml.org/
- https://github.com/raml-org/raml-spec/blob/master/versions/raml-10/raml-10.md/
- OAS 3.0 / 2.0 (Swagger)
- (EDA であれば AsyncAPI もサポートを開始)
## REST API > HTTP メソッド
GET, POST, PUT, DELETE, PATCH...
## クエリパラメータ vs URI パラメータ
### クエリパラメータ (?/&)
フィルタリングをするために使用する
- GET:/customers **?country=JP**
- 日本のお客様情報を取得
- GET:/palyers **?position1=pitcher**
- ピッチャーの選手情報を取得
- GET:/palyers **?position1=pitcher&position2=outfielder**
- ピッチャー兼外野手のどちらにも当てはまる、選手情報を取得
- Ohtani san!
※2つ以上のパラメータを使用する場合には ? と & を使用する
### URI パラメータ ({xxx}) // 波括弧部分は動的に変更されることを示しています
- GET:/customers/1234
- /customers/**{custId}**
- 1234の固有のIDを持った、お客様情報を取得 ("1"人)
- GET: http://api.soccer.restapi.org/leagues/{leagueId}/teams/{teamId}/players/{playerId}
- /leagues/**EU02**/teams/**10**/players/**651**
### RAML
YAML がベース = インデントが命! (Q6)
```
/customers:
get:
queryParameters:
```
エラー
```
/customers:
get: # get メソッドのインデントに問題あり
queryParameters:
```
## RAML フラグメント(部品)
データ型(data type), データ例(data example)..
## フラグメントの参照方法
`!include` (Q7)
# 3. Mule Eventの参照と変更 (開発:基礎 モジュール6)
## Mule Event

- Mule Event (Mule イベント)
- *Mule Message (Mule メッセージ)*
- **Attributes** (属性: データの付随情報 (クエリパラメータ、ヘッダー、URI パラメータ))
- GET:/customers?id=48493
- `#[attributes.queryParams.id] `>>> `48493`
- `#[attributes.headers.method]` >>> `GET`
- GET:/customers/48493
- `#[attributes.uriParams.id] ` >>> `48493`
- `#[attributes.headers.method]` >>> `GET`
- **Payload** (ペイロード: データの本体)
- `#[payload]` {"year": 2022}
- `#[payload.year]` >>> 2022
- **Variables** (変数)
- `#[vars.hogeFlag]` >>> `true`
- `#[vars.tranId]` >>> `41674810`
- `#[vars.theResult]`
## Q10 "The year is 2020"
- payload
```
{
"year":"2020" // payload.year => "2020"
}
```
- `#["The year is 2020"]` // ハードコード
- "The year is 2020" // ハードコードなしで、これをログ出力したい
`#[ ]`// DataWeaveでの記述である合図
1. `#["The year is" ++ payload.year]`// ++ concatination 結合の関数
2. `The year is #[payload.year]`
## Target Variable (Q13)


### Target Variable (ターゲット変数)
- いま持っている payload を上書きせずに、外部のシステムからデータを取得し、Mule Event の Variables に保存するための設定
- 変数名を指定して、payload にデータを入れる (=上書きする) 代わりに、取得したデータを変数にセットします
- 各コネクタの Advanced タブにて設定
## typeOf(データの型をチェック) Q14
`typeOf("The year is 2020")`// `String`
`typeOf(1234)` // `Number`
`typeOf(true)` // `Boolean`
`typeOf(null)` // `Null`
`typeOf({"hoge":"2021"})` // `Object`
`typeOf([1,2,3])` // `Array`
```
%dw 2.0
output application/xml // フォーマットを指定
---
payload
```
## DataWeave Playground(ブラウザベースのテスト環境)
https://developer.mulesoft.com/learn/dataweave/
## payload を上書きしないための2つの方法(Q16)
1. target variable を使用する (新しいデータで、今ある payload を上書きしない)
2. 変数 (vars) は上書きされないので、上書きされたくないデータは、payload ではなく vars に入れておく
- Event
- Message
- Attributes
- `#[queryParams.color]` >>> `red`
- `#[payload]` >>> `"Order01"`
- Vars:
- `#[vars.quantity]` >>> `1`
# 4. Mule アプリケーションの構造化 (開発:基礎 モジュール7)
## コネクタ設定 > グローバル要素(global element)
1度設定したコネクタの設定は、別の xml や別フローで再利用することが可能
## 同一アプリケーションの別フローを HTTP Request で呼び出すと.. (Q18)
HTTP はクライアントとサーバーのやりとりのためのプロトコルであり、
サーバー側にそのままの Mule Event を渡すことができない
=> 新たな 別 Mule Event が、呼び出された側のフローで生成されてしまう
- パフォーマンスの問題??? (ネットワークのホップ, TCPハンドシェイク etc...)
## Flow Reference (Q19)
- 同一 Mule アプリケーションの別フローを呼び出す
- payload, attribtues, variables など、フローを跨いで共有可能
## yaml/propertiesの設定を動的に参照する(Q20)
プロパティのプレースホルダーで、コネクタ設定のハードコードを回避
`${training.db.host}`// 動的にyamlの値を取りに行く
config.yaml
```
traininig:
db:
host: "here.is.what.is.taken.from.the.expression"
```
## 参照するyamlの設定(Q21)
Global Element > Configuration properties

`${env}-config.yaml`// 参照するyamlファイルを、${env}環境変数でコントロールすることも可能
- DataWeave からは `p('db.port')`の形式で参照可能
# 5. API 実装のためのインターフェース
## API Kit
- RAML仕様から、土台となるインターフェースフローを自動生成してくれるツール
- APIKit を使用して、インターフェースフローを自動生成する (scaffolding = 土台作り)
- API 仕様に基づいたバリデーションも自動生成
- 必須のパラメータがなかったら _400 Bad Request_
## APIKit 仕様から API のインターフェースを自動生成する(sccafold)
方法1. プロジェクト名を右クリック > Manage APIs > 管理する API を新規追加
方法2. 右クリック > New > Mule Project > Exchange, Design Center, もしくはローカルファイルから API 仕様を読み込ませる
※ Anyoint Platform アカウントへのログインが必要
# 6. コネクタの活用
外部のシステムとの連携をシンプルに、スピーディーにするためのモジュール
- HTTP, Slack, SAP, Salesforce, ServiceNow, Google Drive, Kafka, Database...
## REST Connect コネクタ
- RAML/OAS から自動生成されるコネクタ
- Exchange に API 仕様を公開したタイミングで自動生成される
- REST API 呼び出しの複雑さをラッピングする
- 必須のパラメータ
- クエリパラメータ
- オペレーションとして ドラッグ&ドロップが可能になる (vs 手動で HTTP リクエストを設定)
- HTTP メソッド
- パス
```
/flights:
get:
displayName: getFlights(フライト情報を取得)
description: アメリカン航空のフライト情報を JSON <Array.Object>で取得
```
※ RAML の displayName を変更すれば、日本語のオペレーション名にすることも可能
## Q27 WHERE の条件に当てはまらない場合の return value
`SELECT * FROM aTable
WHERE ID = 100;` >>> `[]` //空の配列
## Q28 Database のオペレーションで、Mule Event の値を使用する
`:(コロン)` を使用して、Input Parameters セクションとマッピングする
`INSERT INTO orders.ORDER(orderId, cutomerName, status, startDate)
VALUES (:oid, :custId, :status, now())
`// now() は DBの関数
Input Parameters(Mule Event を使用可能)
```
#[{
oid: payload.oid,
custId: payload.custId,
status: payload.status
}]
```

## Q29 ++ 関数を Object に使用する
https://developer.mulesoft.com/learn/dataweave/
```
%dw 2.0
output application/json
---
{
tran_id: 1234,
account_id: 999,
name: "Max",
position: "sell"
}
++ {date: (now() >> "JST" as TimeZone)}
// ++ オブジェクトにフィールドを追加。*++* は、その他文字列の結合、配列の結合にも使うことができる
```
```
{
tran_id: 1234,
account_id: 999,
name: "Max",
position: "sell",
date: |2022-02-21T04:45:44.946157Z|
}
```
## Q30 JMS, VM コネクタの非同期処理
- Publish
- キューにメッセージを追加 (非同期)
- Fire & Forget
- Publish Consume
- キューにメッセージを追加し、処理の完了まで待つ (同期)
### Q31
1. HTTP Listner
2. DB Select // 結果はpayloadに保存
3. Set Variable // `#[vars.dbResult] = payload`
4. HTTP Request // 結果はpayloadに保存
DBのデータ: `#[vars.dbResult]`
HTTP Requestのデータ: `#[payload]`
# 7.レコードの処理
- For Each
- シングルスレッド
- 同期処理
- sequential (順番に) 処理を行う
- batch block size (デフォルト 1)
- [1,2,3,4,5] >>> 1 -> 2 -> 3 -> 4 -> 5
- batch block size (2)
- [1,2,3,4,5] >>> 1,2 -> 3,4 -> 5
- For Each スコープの中で、payload を書き換えても (e.g. Set Payload)、**For Each スコープを終えれば、payload はスコープに入る前の元々のデータを保持し続ける**
- 変数は、全てのループで共有される
- For Each スコープの前で宣言された変数も、For Each スコープ内で参照・変更・削除可能

- Batch Job
- マルチスレッド
- 非同期処理
- parallell(並列に)処理を行う
- 変数は、各レコードに固有のもの
- レコード1 `#[vars.hoge = true]`
- (レコード1 の `#[vars.hoge]`は、そのまま BatchStep A, B, C で参照・変更可能)
- レコード2 ``#[vars.hoge = false]`
- (レコード2 の `#[vars.hoge]` は、そのまま BatchStep A, B, C で参照・変更可能)
- Batch Step
- Batch Jobの処理の単位
- Batch Jobは1つ以上のBatch Stepで構成されている
- それぞれの Step は、それぞれの条件に基づいて、レコードを受け入れる (acceptPolicy, acceptExpression)
- e.g. acceptExpression: `#[vars.hogeFlag==true]`
acceptPolicy: `ONLY_FAILURES` (処理に失敗したレコードだけを処理する Batch Step)
- Batch Aggregator
- Bulk Insert など、まとめて処理を行う
- 2種類の設定
1. Fixed Size (固有のサイズ)
2. Streaming
- maxFailedRecords
- 失敗したレコードを許容する数 (デフォルト 0)
- batchBlockSize
- 各スレッドがどのくらいの単位で、各レコードをまとめて処理するか (デフォルト100)
e.g. 1000 レコード -> batch block size == 100
- 1-100(100単位)
- 101-200(100単位)
- 201-300(100単位)
...
- 901-1000(100単位)
もし、batch block size が1で、4つのレコードを処理する場合...

- onComplete フェーズで、payloadはサマリーレポートに置き換わる
```
{
"onCompletePhaseException": null,
"loadingPhaseException": null,
"totalRecords": 2000,
"elapsedTimeInMillis": 8909,
"failedOnCompletePhase": false,
"failedRecords": 1,
"loadedRecords": 2000,
"failedOnInputPhase": false,
"successfulRecords": 1999,
"inputPhaseException": null,
"processedRecords": 2000,
"failedOnLoadingPhase": false,
"batchJobInstanceId": "9d6a7e50-5bd0-11ec-8902-a483e7ab0cd9"
}
```
※変数は、各 Batch Step を超えて参照・変更ができる
※Batch Job スコープの完了後は、各変数を参照することはできない
## ウォーターマーク
重複して処理をしないために、前回のフロー実行時に処理した値のうち、最大の値 (ID) を記憶しておく
e.g 前回の実行時 102 まで処理完了 > 次は 103 以上の値を処理する
- 自動
- Database: On Table Row
- File: On New or Updated File
- 手動
- Object Store: Key-Value ペアのストレージ
Object Store を使用して、あるフローの前回の実行時の状態を記録しておくことが可能
# 8.データの変換 (開発:基礎 モジュール11)
## Q38 関数
```
fun newProdCode(prodCode:Number, prodCategory:String):String =
prodCode as String ++ prodCategory
var newProdCode2 = (prodCode:Number, prodCategory:String):String
-> prodCode as String ++ prodCategory
```
https://developer.mulesoft.com/learn/dataweave/
- DW の関数宣言
- fun
`fun funName (arg1, arg2) = arg1 ++ arg2;`
- var
`var funName = (arg1, arg2) -> arg1 ++ arg2;`
- [lookup](https://docs.mulesoft.com/dataweave/2.4/dw-mule-functions-lookup)
`lookup("aFlowName", {})`
// フローの名前, payload を引数に渡す
- モジュールの import
https://docs.mulesoft.com/dataweave/2.4/dw-strings
モジュールのみインポート
```
import dw::core::Strings
Strings::pluralize("child")
```
モジュールから関数をインポート
```
import pluralize from dw::core::Strings
pluralize("child")
```
モジュールから全ての関数をインポート
```
import * from dw::core::Strings
pluralize("child")
```
```
dw::core::Strings::pluralize("child")
```
※ now() など Core モジュールに入っているものは import なしで使える
確認事項: セレクタ(`.` , `..`, `.*`), 演算子, Core モジュール DW 関数 (`map`, `orderBy` etc), XML -> Java, Java -> JSON , type(型, as String), @ で XML アトリビュートを操作する
# 9. ルーティング (開発:基礎 モジュール9)
- Choice
- if, else-if, else
- Scatter-Gather
- マルチスレッド
- 並列処理
- 非同期に、複数のルートを処理する
- 結果を、複数の Event を含むオブジェクトで返す
```
{
"0": {
...
payload: ...
...
}
...
"1": {
...
payload: ...
...
}
}
```
- First Successful //参考程度
- あるルートの処理が成功したら、そこで完了して次のプロセッサへ
- Round Robin //参考程度
- フロー実行時ごとに、順番に実行 (0 -> 1 -> 2 -> 0 -> 1 ...)
# 10.エラー処理
## Q49 グローバルエラーハンドラー(アプリケーションエラーハンドラー)
global elementes > configuration > default error handler

## エラーハンドラのスコープ
0. Mule デフォルトエラーハンドラ
- カスタマイズ不可
1. **アプリケーション(グローバルエラーハンドラ)**
- *エラーハンドラが設定されていない時に限り*、実行されるバックアップ用エラーハンドラ
2. **フローレベル** のエラーハンドラ
- 設定されたフローで起きたエラーを処理
3. **プロセッサレベル** のエラーハンドラ
- Try スコープで設定された範囲で起きたエラーを処理
## エラーハンドラの種類
1. On Error Propagate
- エラーを伝播する (エラーが起きた際に、エラーを再スローする)
2. On Error Continue
- エラーを伝播しない (エラーが起きた際に、エラーを再スローせずに飲み込む)
## Error Object
- Mule Event
- Message
- attributes
- payload
- Variables
- **Error** (エラーオブジェクト)
- _errorType_ (HTTP:NOT_FOUND, HTTP:BAD_REQUEST) \<Object\>
- _namespace_ (名前空間) \<String\>
- HTTP, VALIDATION etc
- _identifier_ (識別子) \<String\>
- NOT_FOUND, BAD_REQUEST
- _description_ \<String\>
- エラーの詳細
Error When
`#[error.errorType.namespace=="HTTP"]`
# 11.アプリケーションのデバッグとトラブルシューティング (DEV:FUN4 モジュール 6)
- DEV:FUN4 モジュール 6 >>> デバッガーの使用方法
# 12.アプリケーションのデプロイと管理 (DEV:FUN4 モジュール 5)
- CloudHub
- MuleSoftがホストする Mule ランタイム実行環境
- CloudHub ワーカーというクラウド上の仮想マシンで、Mule ランタイムをホストし、そこで Mule アプリケーションを実行する
- 内部的に AWS を使用 (CloudHub ワーカーは、AWS 上の VM (EC2 インスタンス))
- 管理のリソースを最小に抑えることができる(多くの部分を MuleSoft が管理・ホストする)
- Runtime Manager
- ランタイムやアプリケーションのデプロイを管理する
- API Manager
- Proxy アプリケーションを作成 (Endpoint With Proxy) し、実装を保護・管理するためのポリシーを適用する
- Basic Endpoint という、保護・実装の一体型の仕組みもあります

- Autodiscovery(オートディスカバリー)
- API を保護するための仕組み。ID (Autodiscovery ID) でAPIの保護を管理している
- API Manager は Autdiscovery ID をもとに「どの API に、どのような保護を実行するべきか」を管理
# その他
皆さんからのフィードバックを活かし、MuleSoft のトレーニングと資格試験をより良いものにしていきます。
ぜひ、[アンケート](https://salesforce.quip.com/Ed56AdCkBwDb)にご協力お願い致します!
おまけ: https://www.youtube.com/watch?v=FNDDfsT152M