<mule>
<http:listener-config name="HTTP_Listener_config">
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<db:config name="Database_Config">
<db:my-sql-connection host="localhost" port="3306" user="admin" password="admin" database="usersdb" />
</db:config>
<flow name="GET-Users-FLOW">
<http:listener config-ref="HTTP_Listener_config" path="/users"/>
<db:select config-ref="Database_Config">
<db:sql ><![CDATA[SELECT * FROM USERS]]></db:sql>
</db:select>
</flow>
<flow name="GET-User-By-Id-FLOW">
<http:listener config-ref="HTTP_Listener_config" path="/userById" />
<db:select config-ref="Database_Config" >
<db:sql ><![CDATA[SELECT * FROM USERS WHERE :userIdParameter == userID]]></db:sql>
<db:input-parameters ><![CDATA[#[{userIdParameter: attributes.queryParams.id}]]]></db:input-parameters>
</db:select>
</flow>
</mule>
Converting a Mule Project to an APIkit Project
If you choose a backend-first design approach for Mule projects and applications that contains business logic, you can convert them into an APIkit project and expose them as REST services. Use one of these approaches:
Consider the size and complexity of the application when deciding on the best approach.
The examples for these approaches are based on the following Mule application that retrieves users from a database:
Before You Begin
To define the API specification for your service, see Design Your API Specification When Building, Implementing, and Testing a REST API. To illustrate this example, create or copy the API specification and JSON example used in that workflow to the /src/main/resources/api
folder.
Manual Approach
Follow these steps to configure a functional router for your existing flows manually.
Step 1: Create a Main Flow
Within the APIkit project, create a main flow that serves as the entry point:
-
Drag the following components from the Mule palette to the canvas:
-
An HTTP Listener source as a flow source
-
An APIkit Router operation within the flow process
-
-
In the properties editor for HTTP Listener in Connector Configuration, select the existing HTTP_Listener_Config.
-
Specify a listener path for the APIkit router by entering
/api/
in *Path. -
In the properties editor for the APIkit router, in Router Configuration, click Add to create a new configuration.
The Global Element Properties wizard appears.
-
In API Definition, select the
api/api.raml
path. -
Accept the configuration.
-
Delete HTTP Listener from
GET-Users-FLOW
. -
Delete HTTP Listener from
GET-User-By-Id-FLOW
.
<mule>
<apikit:config outboundHeadersMapName="outboundHeadersMapName" httpStatusVarName="httpStatus" name="Router" api="api/api.raml" />
<http:listener-config name="HTTP_Listener_config">
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<db:config name="Database_Config">
<db:my-sql-connection host="localhost" port="3306" user="admin" password="admin" database="usersdb" />
</db:config>
<flow name="apiFlow">
<http:listener config-ref="HTTP_Listener_config" path="/api/*"/>
<apikit:router config-ref="Router"/>
</flow>
<flow name="GET-Users-FLOW">
<db:select config-ref="Database_Config">
<db:sql ><![CDATA[SELECT * FROM USERS]]></db:sql>
</db:select>
</flow>
<flow name="GET-User-By-Id-FLOW">
<db:select config-ref="Database_Config" >
<db:sql ><![CDATA[SELECT * FROM USERS WHERE :userIdParameter == userID]]></db:sql>
<db:input-parameters ><![CDATA[#[{userIdParameter: attributes.queryParams.id}]]]></db:input-parameters>
</db:select>
</flow>
</mule>
Step 2: Map API Resources and Actions to Flows
By default, each APIkit flow adheres to a naming convention for routing purposes, characterized by the following pattern:
action:\resource[:content-type][:config-name]
Name | Description |
---|---|
|
HTTP method |
|
HTTP resource |
|
Payload content-type (optional) |
|
APIkit router configuration name (optional) |
To retain the original flow names and map each API resource and action to them, override this behavior by following these steps:
-
Select APIkit Router to open the Properties Editor.
-
In Router configuration, click Edit.
The Global Element Properties wizard appears.
-
In Mappings, click
Add
to create a new mapping configuration.The New Mapping dialog appears.
-
Use the drop-down to map the resources to actions.
-
In Resource, select
/users
. -
In Action, select Get.
-
In Flow, select
GET-Users-FLOW
. -
Click OK.
-
-
In Mappings, click Add.
The New Mapping dialog appears.
-
Use the drop-down to map the resources to actions.
-
In Resource, select
/users/userbyid
. -
In Action, select
Get
. -
In Flow, select the flow that contains the get users action:
GET-User-By-Id-FLOW
. -
Click OK.
-
<mule>
<apikit:config outboundHeadersMapName="outboundHeadersMapName" httpStatusVarName="httpStatus" name="Router" api="api/api.raml" >
<apikit:flow-mappings >
<apikit:flow-mapping resource="/users" action="get" flow-ref="GET-Users-FLOW" />
<apikit:flow-mapping resource="/users/userbyid" action="get" flow-ref="GET-User-By-Id-FLOW" />
</apikit:flow-mappings>
</apikit:config>
<http:listener-config name="HTTP_Listener_config">
<http:listener-connection host="0.0.0.0" port="8081" />
</http:listener-config>
<db:config name="Database_Config">
<db:my-sql-connection host="localhost" port="3306" user="admin" password="admin" database="usersdb" />
</db:config>
<flow name="apiFlow">
<http:listener config-ref="HTTP_Listener_config" path="/api/*"/>
<apikit:router config-ref="Router"/>
</flow>
<flow name="GET-Users-FLOW">
<db:select config-ref="Database_Config">
<db:sql ><![CDATA[SELECT * FROM USERS]]></db:sql>
</db:select>
</flow>
<flow name="GET-User-By-Id-FLOW">
<db:select config-ref="Database_Config" >
<db:sql ><![CDATA[SELECT * FROM USERS WHERE :userIdParameter == userID]]></db:sql>
<db:input-parameters ><![CDATA[#[{userIdParameter: attributes.queryParams.id}]]]></db:input-parameters>
</db:select>
</flow>
</mule>
Scaffolding Approach
Follow the process at Before You Begin. When completed, include an alternative workflow for scaffolding your API specification.
With this approach, you get the APIkit router configuration, error handler, and console flow out of the box. You also get a flow that maps each resource.
Step 1: Scaffold Your API Specification
Scaffold your API to auto-generate the main, console, and resources flows:
-
In Package Explorer, right-click
/src/main/resources/api/api.raml
. -
Select Mule.
-
Click Generate Flows from Local REST API.
A new XML file with the same name as the API is created. This file contains the scaffolded flows.
Step 2: Reference Flows
Do either of the following:
-
Delete the scaffolded flows for each resource and map the original flows as described in Step 2: Map API Resources and Actions to Flows.
-
Remove all operations from the scaffolded flows and add a flow reference that contains the removed operations. By choosing this option, you introduce an additional layer of indirection because you reference all flows to the flow that has the operations, and such indirection can be inconvenient in some scenarios.
<mule>
...
<flow name="get:\users\userbyid:api-config">
<flow-ref name="GET-User-By-Id-FLOW"/>
</flow>
<flow name="get:\users:api-config">
<flow-ref name="GET-Users-FLOW"/>
</flow>
</mule>
-
Transfer the content of the existing flows to the scaffolded flows that adhere to the routing naming convention. If the application is large, performing these modifications can be a laborious task.
<mule>
...
<flow name="get:\users:api-config">
<db:select config-ref="Database_Config">
<db:sql ><![CDATA[SELECT * FROM USERS]]></db:sql>
</db:select>
</flow>
<flow name="get:\users\userbyid:api-config">
<db:select config-ref="Database_Config" >
<db:sql ><![CDATA[SELECT * FROM USERS WHERE :userIdParameter == userID]]></db:sql>
<db:input-parameters ><![CDATA[#[{userIdParameter: attributes.queryParams.id}]]]></db:input-parameters>
</db:select>
</flow>
</mule>
Test Your API
Now that your new project is set up, you are ready to test your API.