12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Mule ESBを使ってデータベースへのRESTfulなWeb APIを作る

Last updated at Posted at 2018-07-11

自己紹介

十川 亮平 (そごう りょうへい) Twitter: @rsogo

NCデザイン&コンサルティング株式会社で
モバイル向けのプラットフォーム (AppPot http://apppot.jp/) のプロダクトマネージャーや、モバイルやIoTの企画や技術面のコンサルタントをやってます。

Mule ESBを利用している開発者の一人としてお話しさせていただきます。


今日は

Mule ESBを使ってデータベースにアクセスするためのRESTfulなWeb APIを作るのを題材に、
Mule ESBを使った開発について話します。

内容としては、次のようなトピックを含みます。

  • HTTP Listener
  • DB Connector
  • メッセージ変換
  • エラーハンドリング

Muleとは

Mule ESBはMuleSoft社が開発したオープンソースのESB製品です。
Community Editionでも、基本的な機能やプロトコルに対応しています。

コネクタの一覧は下記のサイトから調べることができます。
https://www.mulesoft.com/exchange/#!/?types=connector&sortBy=name

Anypoint Exchange 2018-07-11 13-31-49.png

パッケージ製品用のアダプターを使いたいなどの追加の機能を使いたい場合にはEnterprise Editionが用意されています。


全体構造

全体構造

GET, POST, PUT, DELETE, GETだけれど取得条件指定など自由にかけるFreeQuery、
という5つの操作を提供するフローを作っています。今日は時間の関係で、GETとPOSTだけご説明します。

データベースのテーブルをリソースと見なして、
任意のリソースにアクセスできるようなデモです。
固定のテーブルにアクセスするだけならもっと簡単にできますが、
こんなこともできますよ、という内容になっています。


1つの操作の構造

一つの操作の構造はこのようになっています。構造のレベルではどの操作も同じです。

flow-diagram.png


RESTfulっぽくするためにやっていること

アドレス可読性

提供する情報がURIで表現されていること。
ex) http://hostname:port/emploee/115

統一インターフェイス

HTTPの一般的なやり方にならう。

HTTPメソッド

情報の取得(GET)、作成(POST)、更新(PUT)、削除(DELETE)

HTTPステータスコード

リクエストが不正(400 BadRequest)、内部的なエラー(500 InternalServerError)


HTTP Listener

フロー全体と、各操作それぞれでListenする条件を定義できます。

Listenerの構造

HTTP Listener

フロー全体のリスナー

こういうhttp://{hostname}:8085/4apppot/{任意}リクエストをリッスンする定義にしています。

<http:listener-config
 name="HTTP_Listener_Configuration"
 host="0.0.0.0" port="8085"
 basePath="4apppot"
 doc:name="HTTP Listener Configuration"/>

1つの操作用のリスナー

フロー全体のリスナーで受け取った上で、GETメソッドで、{basePath}/query/*というパスのリクエストを受け取る。

<flow name="FreeQueryFlow">
   <http:listener config-ref="HTTP_Listener_Configuration"
      path="/query/*"
      doc:name="Receive HTTP request"
      allowedMethods="GET">
     <http:response-builder
         reasonPhrase="#[flowVars['reason']]"
         statusCode="#[flowVars['statusCode']]"/>
   </http:listener>

DBコネクタ

たくさんのコネクタの中から、今回は一番使用頻度が高いかも知れないDatabase Connectorを使います。

JDBCドライバの準備

{MULE_HOME}/lib/user/以下にJDBCドライバのライブラリを入れておく

接続情報の定義

<db:generic-config doc:name="Generic Database Configuration"
     driverClassName="com.mysql.jdbc.Driver"
     name="DB_Configuration"
     url="jdbc:mysql://localhost:3306/{DATABASE_NAME}?user={DB_USER}&amp;password={PASSWORD}&amp;characterEncoding=utf8"/>

Select: GETの時

<db:select config-ref="DB_Configuration" doc:name="Perform a query in Database">
  <db:dynamic-query>
    <![CDATA[select * from #[VarTableName]
    #[VarQuery]]>]
  </db:dynamic-query>
</db:select>

Insert: POSTの時

<db:insert config-ref="DB_Configuration" doc:name="Database">
  <db:dynamic-query>
    <![CDATA[INSERT INTO #[VarTableName] (#[VarInsertColumns]) VALUES (#[VarInsertValues])]]>
  </db:dynamic-query>
</db:insert>

フロー中のメッセージの利用

Muleのフロー定義中ではMEL(Mule Expression Language)というので、メッセージの参照や計算なんかができます。

  • マニュアルからのサンプルの抜粋
#[payload]
#[message.inboundProperties.'propertyName']
#[payload.methodCall(parameters)]
#[xpath3('//root/element1')] 
#[payload.age > 21]
#[message.inboundProperties.'locale'  ==  'en_us']

Mule Expression Language Referenceに使い方の例が載っているので、困ったらここを見たら良いと思います。


JSONとの変換はとっても簡単

リクエストで受け取ったJSONメッセージをオブジェクトに変換

<json:json-to-object-transformer returnClass="java.util.ArrayList" doc:name="JSON to Object"/>

SQL実行結果のオブジェクトからJSONに変換

<json:object-to-json-transformer doc:name="Convert Object to JSON"/>

Mule ESBのエラーハンドリング

エラーハンドリングはこんな感じの書き方になります。

<flow>
    <リクエストの受取/>
    <メッセージ変換など/>
    <連携先の呼び出し/>
    <応答メッセージの編集/>
    <choice-exception-strategy>
        <例外Xが起こったときのハンドリング/>
        <例外Yが起こったときのハンドリング/>
    </choice-exception-strategy>
</flow>

実際にエラー時の応答がRESTfulっぽくなるように書いてみましょう

<flow name="GetFlow">

・・・省略・・・

    <choice-exception-strategy doc:name="Choice Exception Strategy">
        <catch-exception-strategy doc:name="Catch Exception Strategy"
            when="#[exception.causedBy(org.mule.module.db.internal.domain.connection.ConnectionCreationException)]">
            <logger level="INFO" doc:name="Log Request" message="Error processing #[flowVars['originalRequest']]" />
            <set-variable variableName="statusCode" value="500" doc:name="Set status code"/>
            <set-variable variableName="reason" value="Internal Server Error" doc:name="Set reason phrase"/>
        </catch-exception-strategy>
        <catch-exception-strategy doc:name="Catch Exception Strategy"
            when="#[exception.causedBy(org.mule.module.db.internal.resolver.query.QueryResolutionException)]">
            <logger level="INFO" doc:name="Log Request" message="Error processing #[flowVars['originalRequest']]" />
            <set-variable variableName="statusCode" value="400" doc:name="Set status code"/>
            <set-variable variableName="reason" value="Bad Request" doc:name="Set reason phrase"/>
        </catch-exception-strategy>
        <catch-exception-strategy doc:name="Catch Exception Strategy"
            when="#[exception.causedBy(java.sql.SQLSyntaxErrorException)]">
            <logger level="INFO" doc:name="Log Request" message="Error processing #[flowVars['originalRequest']]" />
            <set-variable variableName="statusCode" value="400" doc:name="Set status code"/>
            <set-variable variableName="reason" value="Bad Request" doc:name="Set reason phrase"/>
        </catch-exception-strategy>
        <catch-exception-strategy doc:name="Catch Exception Strategy"
            when="#[exception.causedBy(java.sql.SQLIntegrityConstraintViolationException)]">
            <logger level="INFO" doc:name="Log Request" message="Error processing #[flowVars['originalRequest']]" />
            <set-variable variableName="statusCode" value="400" doc:name="Set status code"/>
            <set-variable variableName="reason" value="Bad Request" doc:name="Set reason phrase"/>
        </catch-exception-strategy>
    </choice-exception-strategy>
</flow>

スクラッチ開発との比較 - Why Mule ESB

サーバーサイドエンジニアが居て、
ある特定のデータソース向けにだけにプログラムを書けば良いのであえれば、スクラッチ開発で良いかも。

ESBのメリット

  • 連携先が複数のデータソース、ソフトウェア、製品などに渡る場合
  • 自分たちがオーナーではないシステムと連携する場合(自分たちの都合でコントロールできない)

Apache Camelとの比較 - Why Mule ESB

Apache CamelはMule ESBと同様にさまざまなプロトコルに対応したインテグレーションのためのソフトウェアです。

  • Java系のソフトウェアに組み込むなら、Camelは選択肢となる
  • ただし、ESB的な用途にはそのままでは使えない
  • 独立したプラットフォームとして使いたいならMule ESB、自分たちで作るソフトウェアに組み込みたいならCamel

まとめ

今日ご説明した内容はQiitaで既に公開しています。

フローの定義の全体はGithubに公開していますので、アクセスしてみてください。
フィードバックもいただけるとありがたいです。
3.xで動作確認をしていますので、最新の4.xでは一部修正が必要です。


最後に

Mule、AnyPoint Platformが日本でもっと使われて、ユーザー同士で情報交換が活発にできるようになると嬉しいです!

12
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?