# 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クライアントへの影響をテストできる ![Q1](https://i.imgur.com/cnT0LvW.png) ある日突然「コンセント」のインターフェースが変わったら... ![malaysia](https://i.imgur.com/iqcC9W0.png) ## :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..) ![](https://i.imgur.com/85GOSWH.png) ## 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](https://i.imgur.com/AwLpK95.png) - 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) ![](https://i.imgur.com/37g44F6.png) ![](https://i.imgur.com/QWAGGMS.png) ### 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 ![q21](https://i.imgur.com/MrM3ear.jpg) `${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 }] ``` ![Input Parameters](https://i.imgur.com/oFsk79l.png) ## 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 スコープ内で参照・変更・削除可能 ![](https://i.imgur.com/ZNzUPNO.png) - 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つのレコードを処理する場合... ![batchblock=1](https://i.imgur.com/1ayUy4v.png) - 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 ![q49](https://i.imgur.com/i2F005Y.jpg) ## エラーハンドラのスコープ 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 という、保護・実装の一体型の仕組みもあります ![proxy](https://i.imgur.com/jYhPHUe.png) - Autodiscovery(オートディスカバリー) - API を保護するための仕組み。ID (Autodiscovery ID) でAPIの保護を管理している - API Manager は Autdiscovery ID をもとに「どの API に、どのような保護を実行するべきか」を管理 # その他 皆さんからのフィードバックを活かし、MuleSoft のトレーニングと資格試験をより良いものにしていきます。 ぜひ、[アンケート](https://salesforce.quip.com/Ed56AdCkBwDb)にご協力お願い致します! おまけ: https://www.youtube.com/watch?v=FNDDfsT152M