diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-acb-activity-bar-icon.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-acb-activity-bar-icon.png new file mode 100644 index 000000000..f26ed4380 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-acb-activity-bar-icon.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-configure-library.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-configure-library.png new file mode 100644 index 000000000..4ed6e228d Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-configure-library.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-connection-config.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-connection-config.png new file mode 100644 index 000000000..255156f15 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-connection-config.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-connection-valid.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-connection-valid.png new file mode 100644 index 000000000..acbae77ff Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-connection-valid.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-driver-configured.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-driver-configured.png new file mode 100644 index 000000000..4c567a96f Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-driver-configured.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-flow-overview.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-flow-overview.png new file mode 100644 index 000000000..c19960005 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-flow-overview.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-library-source-maven.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-library-source-maven.png new file mode 100644 index 000000000..f4c1487a9 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-library-source-maven.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-maven-search-results.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-maven-search-results.png new file mode 100644 index 000000000..bad71fec9 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-maven-search-results.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-mysql-connection.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-mysql-connection.png new file mode 100644 index 000000000..5ca0127f6 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-mysql-connection.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-select-add-connection.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-select-add-connection.png new file mode 100644 index 000000000..bcfe2e700 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-select-add-connection.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-db-select-query.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-select-query.png new file mode 100644 index 000000000..9c135a84a Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-db-select-query.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-munit-run-test-menu.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-munit-run-test-menu.png new file mode 100644 index 000000000..4f2441aa6 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-munit-run-test-menu.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-munit-test-results.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-munit-test-results.png new file mode 100644 index 000000000..d7edd6f77 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-munit-test-results.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-publish-command-palette.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-publish-command-palette.png new file mode 100644 index 000000000..eb1136bd7 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-publish-command-palette.png differ diff --git a/code-builder-home/modules/ROOT/assets/images/tut-flights-scaffold-project.png b/code-builder-home/modules/ROOT/assets/images/tut-flights-scaffold-project.png new file mode 100644 index 000000000..795c26ac0 Binary files /dev/null and b/code-builder-home/modules/ROOT/assets/images/tut-flights-scaffold-project.png differ diff --git a/code-builder-home/modules/ROOT/nav.adoc b/code-builder-home/modules/ROOT/nav.adoc index 066e5833a..6a2d5cc7a 100644 --- a/code-builder-home/modules/ROOT/nav.adoc +++ b/code-builder-home/modules/ROOT/nav.adoc @@ -29,6 +29,15 @@ *** xref:tut-slack-add-condition-to-your-flow.adoc[] *** xref:tut-slack-configure-integration.adoc[] +** xref:tut-flights-api-tutorial.adoc[] +*** xref:tut-flights-design-api.adoc[] +*** xref:tut-flights-implement-api.adoc[] +*** xref:tut-flights-validate-transform-data.adoc[] +*** xref:tut-flights-debug-api.adoc[] +*** xref:tut-flights-munit-test-api.adoc[] +*** xref:tut-flights-deploy-api.adoc[] +*** xref:tut-flights-manage-secure-monitor-api.adoc[] + * xref:ai-enabling-api-project-topic-center.adoc[] // USE AI TO DESIGN AN API SPEC diff --git a/code-builder-home/modules/ROOT/pages/tut-flights-api-tutorial.adoc b/code-builder-home/modules/ROOT/pages/tut-flights-api-tutorial.adoc new file mode 100644 index 000000000..9f742a78d --- /dev/null +++ b/code-builder-home/modules/ROOT/pages/tut-flights-api-tutorial.adoc @@ -0,0 +1,39 @@ += Build an API from Start to Finish with Anypoint Code Builder +:imagesdir: ../assets/images +:page-pagination: next + +Take an end-to-end, API-led journey in MuleSoft: design a REST API specification, implement it as an integration, debug and test your application, deploy it, and then manage and monitor it in production. This tutorial walks you through that full lifecycle using a single-resource API, the American Flights API, that returns flight information from a MySQL database. + +After you complete the tutorial with this single-resource API, use the same model to plan your own connectivity projects. + +This tutorial series contains the following parts: + +. xref:tut-flights-design-api.adoc[] + +Design the American Flights API specification, test it with the built-in mocking service, and publish it to Anypoint Exchange. +. xref:tut-flights-implement-api.adoc[] + +Scaffold the specification into an integration project and connect to a MySQL database. +. xref:tut-flights-validate-transform-data.adoc[] + +Add business logic validation and transform database records to meet the API contract. +. xref:tut-flights-debug-api.adoc[] + +Run the application locally and use the debugger to trace request execution and error routing. +. xref:tut-flights-munit-test-api.adoc[] + +Create and run MUnit tests to verify your API behaves correctly. +. xref:tut-flights-deploy-api.adoc[] + +Deploy the application to CloudHub 2.0. +. xref:tut-flights-manage-secure-monitor-api.adoc[] + +Register the API with API Manager, secure it with a policy, and monitor it with Runtime Manager. + +== Before You Begin + +Before you begin your API journey, verify that you have the required tools and access: + +* Set up your MuleSoft environment. ++ +See xref:start-acb.adoc[] for more information. +* Create an account on Anypoint Platform. ++ +Use your username and password for your Anypoint Platform organization. If you don't have an Anypoint Platform account yet, create a trial organization. +* Download a REST client, such as Advanced REST Client or another similar client, to test REST requests. This tutorial uses Advanced REST Client. +* Have some familiarity with xref:access-management::business-groups.adoc[business groups]. API specs must belong to a business group to be published to Exchange. + +TIP: Configure a long timeout in your REST client settings to avoid timeout issues during debugging. diff --git a/code-builder-home/modules/ROOT/pages/tut-flights-debug-api.adoc b/code-builder-home/modules/ROOT/pages/tut-flights-debug-api.adoc new file mode 100644 index 000000000..69d2340d1 --- /dev/null +++ b/code-builder-home/modules/ROOT/pages/tut-flights-debug-api.adoc @@ -0,0 +1,141 @@ += Debug the American Flights API +:imagesdir: ../assets/images +:page-pagination: + +After implementing your API flows, validate that the application behaves as expected before writing automated tests. In this section, you run the project locally and use the debugger to trace request execution and error routing. + +== Run the Application Locally + +Before testing your API, start the Mule application locally to verify the implementation works as designed. + +. In Anypoint Code Builder, open your implementation project and verify that the listener in `american-flights-api-main` is configured for host `0.0.0.0` and port `8081`. +. Click the *Listener* element in your flow. +. On the *Connection Config* field, click *Edit Connection*. +. Verify the values and update them if necessary: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Host* | `0.0.0.0` +| *Port* | `8081` +|=== ++ +// Pointer to Run and Debug +include::partial$acb-reusable-steps.adoc[tags="open-run-debug"] +. In the top menu, ensure *Run Mule Application* is selected and click *Start Debugging*. +. Wait for the application to deploy. You see deployment messages in the *Output* panel. ++ +When deployment is complete, you see a message similar to: ++ +[source,command] +---- +********************************************************************** +* - - + APPLICATION + - - * - - + STATUS + - - * +********************************************************************** +* american-flights-api-implementation-1.0.0 * DEPLOYED * +********************************************************************** +---- +. In your REST client (such as Advanced REST Client), test your API endpoints: +* Send `GET http://localhost:8081/api/flights` and verify a `200` response with flight data. +* Send `GET http://localhost:8081/api/flights/AA123` and verify the flight-by-ID response path works. +* Send `GET http://localhost:8081/api/flights/123` and verify a `400` response from your API specification's path parameter validation. + +== Understand the Debugger + +The built-in debugger in Anypoint Code Builder helps you understand how your Mule application processes requests, inspect variable values at runtime, and trace error-handling paths. + +Breakpoints pause execution at specific components in your flow, so you can inspect the current state of the message payload, attributes, and variables. There are two types of breakpoints: + +* *Component Breakpoint*: Pauses execution before a specific component executes (such as a Transform Message or Database Select operation). +* *Error Breakpoint*: Pauses execution when an error occurs, allowing you to inspect the error object. + +When the application running in debug mode reaches a component with a breakpoint, execution pauses and the IDE highlights the current component with a yellow border. + +The *Debug* panel opens automatically, showing the current values of Mule variables, message attributes, payload, and the flow execution path leading to the current breakpoint. + +== Set Component Breakpoints + +Set breakpoints in your application to pause execution and evaluate values at runtime. + +. With your application stopped, open the canvas view of your `american-flights-api-implementation.xml` file. +. Locate the flow `get:\flights\(flightId):american-flights-api-config`. +. Right-click the *Flight by ID* Database Select operation. +. Select *Add Breakpoint* from the context menu. ++ +A red dot appears on the component, indicating an active breakpoint. +. Add a breakpoint on the *Transform Flight* component after the database query to inspect the payload. + +== Start a Debug Session + +. Click the *Run and Debug* icon in the activity bar. +. Ensure *Debug Mule Application* is selected in the dropdown. +. Click the *Start Debugging* button (green play icon). +. Wait for the application to deploy in debug mode. You see `Debugger listening on port XXXX` in the output panel. + +== Step Through the Execution and Inspect Variables and Payload + +. After your application starts running in debug mode, send a request from your REST client: ++ +[source,command] +---- +GET http://localhost:8081/api/flights/AA123 +---- ++ +The execution pauses at the *Flight by ID* breakpoint. +. In the *Variables* section of the Debug panel, expand *Mule Message > Payload*. ++ +At this point, the message is empty because the query to the database hasn't executed. +. Expand *Mule Message > Attributes* to see HTTP request information: +* `attributes.uriParams.flightId`: The flight ID from the URL. +* `attributes.headers`: HTTP headers. +* `attributes.method`: HTTP method (GET, POST, and so on). +. Expand *Variables* to see Mule variables created by Transform Message components: +* `vars.flightCodeMap`: The flight code mapping. +* `vars.dbFlightId`: The database ID for the flight. +. To evaluate a DataWeave expression at the current breakpoint: +.. In the Debug panel, locate the *Watch* section. +.. Click the *+* icon to add a watch expression. +.. Enter a DataWeave expression, such as: ++ +[source,dataweave] +---- +attributes.uriParams.flightId +---- +.. Press Enter. The IDE evaluates the expression and displays the result. +. Click *Step Over* (or press F10) to continue the execution. +. Execution stops at the *Transform Flight* component. +. Expand *Mule Message > Payload*. ++ +Notice that now the message contains the results from the database query. +. Click *Stop* (SHIFT+F5) to finish debugging. + +== Debug Error Paths + +To understand how your API handles errors, debug the validation and error-handling logic. + +. Set breakpoints on: +* The Choice router in `get:\flights\(flightId):american-flights-api-config`. +* The Raise Error component inside the *When* path. +. Start debugging and send an invalid request in your REST client: ++ +[source,command] +---- +GET http://localhost:8081/api/flights/AA999 +---- ++ +The execution pauses at the Choice router. +. Inspect `vars.dbFlightId` (should be `null` because `AA999` isn't in the mapping). +. Click *Step Over* (F10). ++ +Execution moves to the *When* path and pauses at Raise Error. +. Click *Step Over* (F10). ++ +Execution pauses at the On Error Propagate handler for `VALIDATION:FLIGHT_NOT_FOUND`: +. In the Debug panel, expand the `error` object and verify: +* `error.errorType`: `VALIDATION:FLIGHT_NOT_FOUND` +* `error.description`: `"Flight code AA999 not found in our system"` +. Inspect the Logger component's message evaluation. +. Click *Continue* (F5) to complete the error response. + +Once your application behaves as expected, add automated tests in xref:tut-flights-munit-test-api.adoc[]. diff --git a/code-builder-home/modules/ROOT/pages/tut-flights-deploy-api.adoc b/code-builder-home/modules/ROOT/pages/tut-flights-deploy-api.adoc new file mode 100644 index 000000000..303d12578 --- /dev/null +++ b/code-builder-home/modules/ROOT/pages/tut-flights-deploy-api.adoc @@ -0,0 +1,89 @@ += Deploy the American Flights API to CloudHub 2.0 +:imagesdir: ../assets/images +:page-pagination: + +After implementing, debugging, and testing your API locally, you're ready to deploy it to CloudHub 2.0. CloudHub 2.0 is MuleSoft's cloud-based integration platform that lets you deploy, manage, and scale your Mule applications without managing infrastructure. + +In this section, you deploy your American Flights API to CloudHub 2.0. You configure it in API Manager, apply a security policy, and monitor its performance using Runtime Manager in the pages that follow. + +CloudHub 2.0 provides a fully managed, containerized deployment environment for your Mule applications. Deploying from Anypoint Code Builder is a streamlined process that packages your application and deploys it directly to the cloud. + +See xref:int-deploy-mule-apps.adoc[] for more information about CloudHub and CloudHub 2.0 deployment concepts. + +== Prerequisites for Deployment + +Before deploying to CloudHub 2.0, verify that you have: + +* A CloudHub 2.0 account with available vCores (virtual cores) for deployment. +* Runtime Manager permissions to read, create, and delete applications. +* An application that passes all MUnit tests. +* An application that runs successfully in debug mode locally. + +== Configure Deployment Settings and Deploy Your Project + +The first time you deploy an application to CloudHub 2.0, Anypoint Code Builder creates a deployment settings file. After modifying the deployment settings, deploy your project with those settings. + +. In the project explorer, right-click the American Flights project XML file and select *Mule > Deploy Mule Project to CloudHub*. +. If prompted, sign in to Anypoint Platform. +. Select *CloudHub 2.0*. +. Select a deployment target. +. Select an environment, for example: *Sandbox*. ++ +If there's no deployment settings file for the project, Code Builder creates one. +. In the deployment configuration file, provide the following information: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *applicationName* | Enter a unique name for your deployment (for example, `american-flights-api-yourname`). This name must be unique across all CloudHub deployments. +| *runtime* | Confirm the Mule runtime version (the latest compatible version is selected by default). +| *replicas* | `1`. The number of replica instances to deploy. +| *replicaSize* | `0.1`. The compute capacity (vCores) allocated to each replica. +| *deploymentModel* | Leave the default value: `rolling`. +|=== + +. Click *Deploy* in the notification pop-up. ++ +If the notification is no longer visible, restart the deployment from the first step. +. Select the Mule version to use for the deployment. +. If prompted to select an asset version, leave the default value and press Enter. + +NOTE: Worker size and count affect your CloudHub 2.0 costs. For this tutorial, use 0.1 vCores with 1 worker, which are the minimum allowed values. + +The deployment process starts and usually takes from two to five minutes. After this period, look for an ACB notification with a message similar to this: `The 'american-flights-api-implementation' project was published to the 'Sandbox' environment in CloudHub 2.0 'Cloudhub-US-East-2 - Shared Space'. The deployment is now processing. Monitor its progress in Runtime Manager.` + +== Monitor the Deployment Process + +After initiating the deployment, open Runtime Manager to monitor the status. + +. In the notification that shows after deployment starts, click *Open Runtime Manager* and then click *Open*. +. Alternatively, if you missed the notification, open xref:runtime-manager::index.adoc[Runtime Manager] and search for your application name. Then, click the application name to open its status page. +. Confirm the *Application status* is *Running*. ++ +If the application is still deploying and shows status *Not Running*, wait a few minutes for the process to finish. + +== Verify Your Deployed Application + +Once deployed, verify that your API is accessible and functioning correctly. + +. In Runtime Manager, copy the application URL from the *Public endpoint* value. ++ +The URL is similar to this: `https://american-flights-api-implementation-ij0c18.5sc6y6-3.usa-e2.cloudhub.io` +. In your REST client, test the deployed API by making a GET request to your endpoint and adding `/api/flights` to the URL. For example: ++ +[source,command] +---- +GET https://american-flights-api-implementation-ij0c18.5sc6y6-3.usa-e2.cloudhub.io/api/flights +---- ++ +Replace the URL from the example with your actual endpoint URL. +. Verify that you receive a `200 OK` response with the flight data. +. Test additional endpoints: ++ +[source,command] +---- +GET https://american-flights-api-implementation-ij0c18.5sc6y6-3.usa-e2.cloudhub.io/api/flights/AA123 +---- + +TIP: Save your application URL for use in the next sections where you configure API Manager and apply policies. diff --git a/code-builder-home/modules/ROOT/pages/tut-flights-design-api.adoc b/code-builder-home/modules/ROOT/pages/tut-flights-design-api.adoc new file mode 100644 index 000000000..e509d760d --- /dev/null +++ b/code-builder-home/modules/ROOT/pages/tut-flights-design-api.adoc @@ -0,0 +1,127 @@ += Design and Publish the American Flights API Specification +:imagesdir: ../assets/images +:page-pagination: + +Design the American Flights API specification in Anypoint Code Builder, test it with the built-in mocking service, and publish it to Anypoint Exchange so other team members can find and implement it. + +Before you begin, complete the setup in xref:tut-flights-api-tutorial.adoc[]. + +== Create the API Specification + +Start creating the American Flights API spec: + +// Open the ACB IDE +include::partial$acb-reusable-steps.adoc[tags="open-ide"] ++ +image::tut-flights-acb-activity-bar-icon.png["Anypoint Code Builder icon in the VS Code activity bar"] +. From *Create*, click *Design an API*. +. Configure your API spec project using these values: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Enable this API for Topics and Actions* | Select this checkbox to add the applicable agent topic metadata and apply centralized governance rulesets to the project. ++ +See xref:ai-enabling-api-project-topic-center.adoc[] for more information. +| *Project Name* | `American Flights API` +| *Project Location* | Your home directory is selected by default. ++ +This is the root folder of your project, which acts as your workspace. Don't select a different project directory for this API spec. See xref:start-add-folders.adoc[] for more information. +| *API Type* | *REST API* +| *API Specification Language* | *OAS 3.0 (YAML)* +|=== + +. Click *Create Project* to generate the American Flights API project file: `american-flights-api.yaml`. ++ +The file name is based on the project name you provide. +. Configure the agent topic metadata and instructions using these values: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Topic Label* | American Flights API +| *Classification Description* | Use the API description. +| *Scope* | Your job is only to book, update, or retrieve flight information. +| *Instruction* | If a user asks to retrieve flight details, use the get flight operation to retrieve information using the booking ID. +|=== + +. Click *Apply* to save your changes. +. Open MuleSoft Vibes from the toolbar or from the *Build Your Ecosystem with AI* card in the canvas. +. Enable auto-approve by clicking the *Auto-approve* section at the bottom of the MuleSoft Vibes window, and then select *Read project files*, *Edit project files*, *Execute safe commands*, and *Use MCP Servers*. ++ +With auto-approve enabled, MuleSoft Vibes automatically applies changes to your project without prompting you for confirmation. See xref:vibes-get-started.adoc[] for more information. +. Enter this prompt, and then send your message: ++ +[source,command] +---- +Create an API specification example for the American Flights API that returns flight information from a MySQL database. +---- ++ +MuleSoft Vibes generates the spec and saves it to your file. ++ +NOTE: If you get an `API streaming failed` error, click *Resume Task* to retry creating the spec. + +== Mock and Test the API + +Next, use MuleSoft Vibes and the built-in mocking service in the API Console to test the API before you publish it. + +. Enter this prompt, and then send your message: ++ +[source,command] +---- +Test the API using the built-in mocking service in API console. +---- +. Select the *Auto-approve* checkbox and click *Accept* to proceed with testing. + +MuleSoft Vibes creates a testing file named `API_TESTING_GUIDE.md` and tests these endpoints: + +* `GET` flight data +* `GET` flight status +* `GET` airport information + +MuleSoft Vibes then creates a testing file named `API_TESTING_RESULTS.md`. Your API spec is now ready to publish to Anypoint Exchange. + +== Publish the API Spec to Exchange + +Publish the American Flights API spec to Exchange so that other team members can find and implement it. + +. In Anypoint Code Builder, open the spec for your American Flights API project, such as `american-flights-api.yaml`. ++ +// Pointer to Command Palette +include::partial$acb-reusable-steps.adoc[tags="open-command-palette"] +. Provide this command: ++ +[source,command] +---- +MuleSoft: Publish API Project to Exchange +---- ++ +image::tut-flights-publish-command-palette.png["Command Palette with MuleSoft: Publish API Project to Exchange highlighted"] +. If prompted, click *Allow*, and follow the prompts to sign in to Anypoint Platform. +. If you haven't selected a business group, select one now in *Select a Business Group*. +. Enter the asset version: `1.0.0`. +. Confirm the API version: `v1`. +. Confirm the asset ID in the project metadata: `american-flights-api`. +. Click *Publish*. ++ +The status bar shows the progress after the API is published successfully to Exchange. +. When prompted to implement the API now, select *No* to avoid scaffolding the American Flights API spec into your integration. ++ +Selecting *Yes* scaffolds the API spec into your project. Instead of scaffolding now, you scaffold the API in xref:tut-flights-implement-api.adoc[]. + +=== Locate Your API in Exchange + +After publishing your API spec, you can find it in Anypoint Exchange: + +. Navigate to Anypoint Exchange. ++ +-- +// Pointer to Exchange URLs +include::partial$acb-reusable-steps.adoc[tags="exchange-urls"] +-- +. Type `american` in the search bar and press Enter. +. Notice that your API spec is listed as an asset. ++ +You can select the API, navigate through its summary, and see all the endpoints you defined in the previous tasks. diff --git a/code-builder-home/modules/ROOT/pages/tut-flights-implement-api.adoc b/code-builder-home/modules/ROOT/pages/tut-flights-implement-api.adoc new file mode 100644 index 000000000..f70da6843 --- /dev/null +++ b/code-builder-home/modules/ROOT/pages/tut-flights-implement-api.adoc @@ -0,0 +1,111 @@ += Implement the American Flights API +:imagesdir: ../assets/images +:page-pagination: + +After designing and publishing your API specification, you're ready to implement it in Anypoint Code Builder. At this stage of the tutorial, you already have an API specification for the American Flights API published to Anypoint Exchange, and you're working in the same workspace where you build the integration. + +To implement the API, you scaffold the API specification into an integration project. Scaffolding generates the API interface based on the specification, creating the flows and configuration that you then extend with application logic. + +== Scaffold the American Flights API into an Integration Project + +Now that the American Flights API specification is available in Anypoint Exchange, scaffold it into a new integration project to generate the API interface. + +[tabs] +==== +Use MuleSoft Vibes:: ++ +-- +Ask MuleSoft Vibes to scaffold the locally generated API spec with this message: + +[source,command] +---- +Scaffold the american-flights-api.yaml API spec. +---- +-- + +Manually Scaffold from Anypoint Exchange:: ++ +-- +// Can't reuse because collapsible block conflicts with tab syntax +. Open the Command Palette. +.. Use the keyboard shortcuts: +*** Mac: Cmd+Shift+p +*** Windows: Ctrl+Shift+p +.. Select View > Command Palette. +. Provide this command: ++ +[source,command] +---- +MuleSoft: Implement an API Specification +---- +. In the *Implement an API Specification* tab that opens: +.. Provide a new name for the implementation project. +.. Select or create a new project location. +.. In the search box, type `American Flights API`, or the name you used when creating the specification, and press Enter. +.. Find your API specification on Anypoint Exchange, and click *Add Asset* to insert the API name into the field. +.. Select an existing workspace, or create a new one by providing a name and a location. +.. Click *Create Project* to start scaffolding the specification into a new implementation project. +-- +==== + +After scaffolding completes, confirm that the generated project contains listener configuration, APIKit router flows, and operation-specific flow stubs. + +image::tut-flights-scaffold-project.png["Flow list showing the scaffolded american-flights-api-main flow with a Listener and Router, alongside error handler flows"] + +== Connect to a Database Using the Database Connector + +Add and configure a Database Select operation to retrieve flight data from a database. + +. Open the `get:\flights:american-flights-api-config` flow ++ +image::tut-flights-db-flow-overview.png["The get:\flights:american-flights-api-config flow with an All Flights Database Select component followed by a Transform Message component"] +. Click *Add Component* (+) before *Transform Message*, and then select *Connectors > Database > Select*. +. Click the *Select* component to open its properties panel. +. Change the name to `All Flights`. +. In the *Select* component properties, click *Add New Connection* next to *Connection Config*. ++ +image::tut-flights-db-select-add-connection.png["Database - Select properties panel with the Add New Connection link next to Connection Config"] +. Set the connection to *MySQL Connection*. ++ +image::tut-flights-db-mysql-connection.png["Connection Config dialog with Name set to Config and Connection set to MySQL Connection"] +. Click *Configure library* next to *MySQL JDBC Driver*. ++ +image::tut-flights-db-configure-library.png["Required Libraries section with the Configure library option next to MySQL JDBC Driver"] +. Review the default settings for the recommended library, and in the *Select Library Source* drop-down menu, select *Maven Dependency*. ++ +image::tut-flights-db-library-source-maven.png["Select Library Source drop-down menu set to Maven Dependency"] +. Enter `mysql:` in the *Search Maven Central Repository* text field, and select *mysql:mysql-connector-java* in the results. ++ +image::tut-flights-db-maven-search-results.png["Search Maven Central Repository results showing mysql:mysql-connector-java and other matches"] +. Enter `8.0.30` in the *Version* text field, and click *Apply*. +. Confirm that the MySQL JDBC Driver is set. ++ +image::tut-flights-db-driver-configured.png["Required Libraries section confirming MySQL JDBC Driver is set to mysql:mysql-connector-java:8.0.30"] +. Set the following configuration values: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Host* | `iltdb.mule-training.com` +| *Port* | `3306` +| *User* | `mule` +| *Password* | `mule` +| *Database* | `training` +|=== ++ +image::tut-flights-db-connection-config.png["Connection Config dialog with Host, Port, User, Password, and Database fields set"] + +. Click *Test Connection* and confirm that you see a *Connection is valid* message. ++ +image::tut-flights-db-connection-valid.png["Connection is valid confirmation message"] +. Click *Add* and close the *Database - Select Config* tab. +. In the *Database - Select* properties panel, add a query to select all records from the `american` table: ++ +[source,sql] +---- +SELECT * FROM american +---- ++ +image::tut-flights-db-select-query.png["Database - Select properties panel with the General tab showing the SQL Query Text field set to SELECT * FROM american"] +. In your REST client, test `http://localhost:8081/api/flights`. Confirm that you see a response with all flight data. diff --git a/code-builder-home/modules/ROOT/pages/tut-flights-manage-secure-monitor-api.adoc b/code-builder-home/modules/ROOT/pages/tut-flights-manage-secure-monitor-api.adoc new file mode 100644 index 000000000..01bc682a1 --- /dev/null +++ b/code-builder-home/modules/ROOT/pages/tut-flights-manage-secure-monitor-api.adoc @@ -0,0 +1,209 @@ += Manage, Secure, and Monitor the American Flights API +:imagesdir: ../assets/images +:page-pagination: prev + +After deploying your American Flights API to CloudHub 2.0, register it with API Manager to apply governance policies, secure it with a policy, and monitor its performance and health with Runtime Manager. + +== Manage the API with API Manager + +Use xref:api-manager::api-instance-landing-page.adoc[API Manager] to manage, monitor, and secure your APIs. After deploying your application to CloudHub 2.0, register it with API Manager to apply governance policies, track usage, and control access. + +=== Step 1: Navigate to API Manager + +. Sign in to Anypoint Platform. ++ +// Pointer to Platform URLs +include::partial$acb-reusable-steps.adoc[tags="platform-urls"] +. From the Anypoint Platform home page, click *API Manager* in the navigation menu. +. Select your environment from the environment dropdown (the same environment where you deployed your application). + +=== Step 2: Create an API Instance + +Create an API instance that links your deployed application to the API specification you published earlier. + +. In API Manager, click *Add* and select *Add new API*. +. In the runtime section, select *Mule Gateway* and click *Next*. +. In the *API* section: +.. Click *Select API from Exchange*. +.. Search for "American Flights API" (the API specification you published earlier). +.. Select your API and click *Next*. +. In the *Downstream* section, click *Next*. +. In the *Upstream* section, set the Upstream URL to your application's public endpoint, for example: `https://american-flights-api-implementation-ij0c18.5sc6y6-3.usa-e2.cloudhub.io/`. Click *Next*. +. In the *Review* section, click *Save* to create the API instance. ++ +Verify that your API status now shows *Active*. + +Your API is now registered with API Manager and ready for policy configuration. + +== Secure the API with a Policy + +Policies in API Manager let you enforce security, compliance, and governance rules on your API without modifying application code. In this section, you apply a Client ID Enforcement policy to secure your API. Common policies include: + +* *Client ID Enforcement*: Requires client applications to authenticate using a client ID and secret. +* *Rate Limiting*: Controls the number of requests allowed per time period. +* *IP Whitelist/Blacklist*: Restricts access based on IP addresses. +* *CORS*: Configures Cross-Origin Resource Sharing headers. +* *OAuth 2.0*: Implements OAuth 2.0 authentication and authorization. + +For this tutorial, you apply the Client ID Enforcement policy to require API consumers to register their applications. + +=== Step 1: Apply the Client ID Enforcement Policy + +. In API Manager, navigate to your American Flights API instance. +. Click the *Policies* tab. +. Click *Add Policy*. +. Search for *Client ID Enforcement*, select it, and click *Next*. +. Leave the default settings: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Credentials origin* | Select *customExpression*. +| *Client ID Expression* | `#[attributes.headers['client_id']]` +| *Client Secret Expression* | `#[attributes.headers['client_secret']]` +|=== + ++ +NOTE: This configuration requires clients to pass their credentials in HTTP headers. Alternative configurations can extract credentials from query parameters or custom locations. +. Click *Apply* to activate the policy. + +=== Step 2: Test the Policy + +After applying the policy, verify that unauthenticated requests are rejected. + +. In your REST client, send a request *without* client credentials: ++ +[source,command] +---- +GET http://american-flights-api-yourname.us-e2.cloudhub.io/api/flights +---- +. Verify that you receive a `401 Unauthorized` response: ++ +[source,json] +---- +{ + "error": "Authentication denied." +} +---- + +Then, create a test client application to obtain credentials: + +. In Anypoint Platform, navigate to Exchange. +. Search for your "American Flights API". +. Click *Request Access*. +. In *API Instance*, select your instance. +. In *Application*, select *Create a new application*. +. Provide an application name and click *Create*. +. Click *Request Access*. +. Copy the *Client ID* and *Client Secret* provided. +. Test with credentials. In your REST client, add headers and resend the request: ++ +[source,command] +---- +GET http://american-flights-api-yourname.us-e2.cloudhub.io/api/flights +Headers: +client_id: +client_secret: +---- +. Verify that you receive a `200 OK` response with flight data. + +Your API is now secured and requires authenticated clients to access it. + +=== Policy Best Practices + +When applying policies: + +* *Start with client authentication*: Always require client identification before exposing APIs externally. +* *Apply rate limiting*: Protect your API from abuse by limiting request rates. +* *Use layered security*: Combine multiple policies (authentication + rate limiting + IP filtering). +* *Test thoroughly*: Verify both authorized and unauthorized access scenarios. +* *Document requirements*: Inform API consumers about authentication requirements and rate limits. + +== Monitor and Manage Your Application with Runtime Manager + +xref:runtime-manager::index.adoc[Runtime Manager] is Anypoint Platform's operational dashboard for deployed applications. It provides real-time monitoring, log access, and management capabilities for applications running on CloudHub 2.0. + +Runtime Manager provides: + +* *Application Status*: Real-time status of deployed applications. +* *Performance Metrics*: CPU, memory, and network usage. +* *Logs*: Application logs and system logs. +* *Alerts*: Configurable notifications for application issues. +* *Application Management*: Start, stop, restart, and redeploy applications. +* *Scaling*: Adjust worker size and count. + +=== Step 1: Review Application Status + +. From Anypoint Platform, click *Agent & Tools > Runtime Manager* in the navigation menu. +. In the *Applications* list, locate your application (for example, `american-flights-api-yourname`). +. Click the application name. +. On the side panel, click *Dashboard* to review key information: +* *Status*: Shows whether the application is running, starting, or stopped. ++ +A green indicator with "Running" confirms your application is healthy. +* *Replicas*: Number of replicas and vCores assigned. +* *Last Updated*: When the application was last deployed or updated. +* *URL*: The application's public URL. + +=== Step 2: View Application Logs + +Logs help you troubleshoot issues and monitor application behavior. + +. In the side panel, click *Logs*. +. View recent log entries: +* *Log Level*: Filter by INFO, WARN, ERROR, or DEBUG. +* *Search*: Search for specific log messages or error codes. +* *Time Range*: Adjust the time range to view historical logs. ++ +TIP: If you don't see any entries, select a previously used Config from the dropdown menu. +. Example log entries: ++ +[source,command] +---- +[INFO] Application started successfully +[INFO] HTTP Listener on 0.0.0.0:8081 +[INFO] Deployed application: american-flights-api +---- +. Search for specific events: +* Search for "ERROR" to find errors. +* Search for "flights" to see API-related logs. +* Search for "Database" to see database operations. + +=== Step 3: Monitor Performance Metrics + +Monitor your application's resource usage to ensure it runs efficiently. + +. In the side panel, select *Dashboard*. +. Select the *Performance* tab. +. Review performance metrics such as average inbound and outbound response times. +. Select the *Infrastructure* tab. +. Review metrics such as CPU % and memory usage. + +=== Step 4: Manage Your Application + +Use Runtime Manager to control your application's lifecycle. From the application dashboard, you can: + +* *Stop*: Click *Stop* to stop the application. ++ +The application remains deployed but stops serving requests. +* *Start*: Click *Start* to start a stopped application. +* *Delete*: Click *Delete* to remove the application from CloudHub. ++ +This action is permanent and cannot be undone. +* *Update Configurations*: Click *Apply Changes* after changing configurations such as properties, to restart the application without redeploying. + +=== Step 5: Scale Your Application + +As your API usage grows, scale your application by adjusting worker size or count. + +. From the application dashboard, click *Settings*. +. In the *Deployment Target* section: +* *Replica Count*: Increase the number of workers for horizontal scaling. +* *Replica Size*: Change the worker size (for example, from 0.1 to 0.2 vCores). +. Click *Apply Changes*. +. CloudHub redeploys your application with the new configuration. + +NOTE: Scaling changes the resources allocated to your application and may affect your CloudHub costs. Monitor performance metrics before scaling to ensure it's necessary. + +This concludes the American Flights API tutorial series. You designed an API specification, implemented it as an integration, validated and transformed data, debugged and tested your application, deployed it to CloudHub 2.0, and secured and monitored it in production. diff --git a/code-builder-home/modules/ROOT/pages/tut-flights-munit-test-api.adoc b/code-builder-home/modules/ROOT/pages/tut-flights-munit-test-api.adoc new file mode 100644 index 000000000..bc28c9590 --- /dev/null +++ b/code-builder-home/modules/ROOT/pages/tut-flights-munit-test-api.adoc @@ -0,0 +1,387 @@ += Test the American Flights API with MUnit +:imagesdir: ../assets/images +:page-pagination: + +After debugging your API flows locally, add automated MUnit tests to verify behavior and guard against regressions before deployment. + +Before you begin, complete the debugging steps in xref:tut-flights-debug-api.adoc[]. + +MUnit is MuleSoft's unit testing framework for Mule applications. Use it to create automated tests that verify your API behaves correctly, without requiring external dependencies or manual testing. Anypoint Code Builder provides integrated support for creating, running, and debugging MUnit tests through a Testing panel, canvas UI, and code editor. + +== Understand MUnit Test Structure + +An MUnit test consists of: + +* *Test Suite*: A file containing one or more tests (saved as `*-test.xml` in `src/test/munit`). +* *Test Case*: An individual test that validates a specific behavior. +* *Behavior*: Setup and teardown conditions, including mocks of external systems (like databases) to isolate the logic under test. +* *Execution*: Invokes a flow or subflow. +* *Validation*: Asserts that the result matches expectations. + +NOTE: MUnit 3.4.0 or later is required for canvas-based test suite creation in Anypoint Code Builder. + +== Create Your First MUnit Test Suite + +Create a test suite to verify the `GET /flights` endpoint returns all flights. + +=== Step 1: Create a New MUnit Test Suite + +. In Anypoint Code Builder, navigate to `src/test/munit` in the Explorer panel. +. Right-click the `munit` folder and select *New MUnit Test Suite File*. +. Provide a name for the test suite: `american-flights-api-test.xml`. +. Click *Create*. ++ +Anypoint Code Builder generates a new file with a basic structure: ++ +[source,xml] +---- + + + + +---- + +=== Step 2: Add a Test for Database Operations + +Now create your first test case to verify a database query returns flight data successfully. This test uses the actual database configuration from your implementation project. + +NOTE: This example uses a real database connection. For tests that should run without external dependencies, you can mock the database using `munit-tools:mock-when` as shown later in this section. + +. Open the test file (`american-flights-api-test.xml`) in canvas view. +. In the MUnit bar, click *+* and select *Test Scope*. +. Click the *Test* component and change its name to `test-database-query`. ++ +Alternatively, in the code editor, add: ++ +[source,xml] +---- + + + +---- +. In the *Behavior* section, click *+*. +. Select *Code Processors > Transformers > Set Variable*. +. Click the *Set Variable* component and specify these values: +* *Variable name*: `expectedRecordCount` +* *Value*: `3` ++ +Alternatively, paste this code in your `munit:test` element in the XML config: ++ +[source,xml] +---- + + + + +---- +. In the *Execution* section, click *+*. +. Select *Connectors > Database > Select*. +. Click the *Database - Select* operation and specify these values: +* *Connection Config*: `Config` (select the existing database configuration) +* *SQL Query Text*: `SELECT * FROM american` ++ +Alternatively, paste this code in your `munit:test` element in the XML config: ++ +[source,xml] +---- + + + + + +---- +. In the *Validation* section, click *+*. +. Select *MUnit Test Modules > Assert that*. +. Click the *Assert that* component and specify these values: +* *Expression*: `sizeOf(payload)` +* *Is*: `MunitTools::greaterThan(0)` +* *Message*: `Should return at least one flight` ++ +[source,xml] +---- + + + +---- ++ +This validation checks that the database query returned at least one record. + +=== Step 3: Run the Test + +// Pointer to Testing panel +include::partial$acb-reusable-steps.adoc[tags="munit-open-testing-panel"] +. Locate your test suite `american-flights-api-test.xml` in the Testing panel. +. Click the *Run* button (▶) next to the test case `test-database-query`. ++ +Alternatively, right-click the test in the canvas and select *Run Tests*. +. View the test results in the *Testing* panel. ++ +A successful test shows a green checkmark (✓) and output similar to: ++ +[source,command] +---- +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +---- + +=== Complete Example + +Here's the complete test structure: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + +---- + +== Advanced Testing: Use Mocks for API Endpoints + +While the previous example tested a database operation directly, you can also test complete API endpoints by adding an HTTP Request configuration and mocking dependencies. This approach allows your tests to run without requiring external systems like databases. + +=== Step 1: Add the HTTP Namespace + +Before using HTTP components in your test, you need to add the HTTP namespace to your test suite. + +. Open the test suite file in the XML code editor (click the ** icon to switch from canvas to code view). +. Locate the opening `` tag at the top of your file. +. Add the HTTP namespace declaration to the `` tag: +* Add `xmlns:http="http://www.mulesoft.org/schema/mule/http"` to the namespace declarations. +* Add `http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd` to the `xsi:schemaLocation` attribute. ++ +Your `` tag should look like this: ++ +[source,xml] +---- + +---- + +=== Step 2: Add the HTTP Request Configuration + +Add an HTTP Request configuration that points to your local Mule application. Copy and paste this configuration in the XML editor before your test cases: + +[source,xml] +---- + + + +---- + +=== Step 3: Add a Test for GET /flights (Success Path) + +Create a test that calls your API endpoint and mocks the database response. + +. Open the `american-flights-api-test.xml` file in the Code Editor. +. After the closing `` tag and before the `` tag, paste this code: ++ +[source,xml] +---- + + + + + + + + + + + + + + + + + + + +---- +. Confirm the test was created in the canvas view. + +NOTE: The `with-attributes` section identifies which specific Database Select operation to mock by matching the `doc:name` attribute value. Make sure the `whereValue` matches the name you gave to your Database Select component in the implementation flow. + +=== Step 4: Add a Test for Error Handling + +Add a new test to verify error handling when a flight code is not found. + +. After the last closing `` tag and before the `` tag, paste this code: ++ +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + + + + +---- + +=== Step 5: Run the Tests + +. Open the test in canvas view. +. In the Testing panel, click the *Run all tests in this file* (▶) button. +. Click *Run Test*. ++ +image::tut-flights-munit-run-test-menu.png["Testing panel run button menu with Run Test and Run Test with Coverage options"] +. Verify the tests pass with the expected responses. ++ +image::tut-flights-munit-test-results.png["Testing panel showing 3 of 3 tests passed for the american-flights-api-test.xml suite"] + +== Measure Test Coverage + +MUnit provides built-in coverage reporting that measures the percentage of event processors executed by your tests. Aim for at least 80% coverage for production APIs. + +After you run tests with coverage, you can view the results in the *Test Coverage* panel or in the console output. The Explorer panel also displays coverage metrics alongside your files, making it easy to identify which parts of your application need additional test coverage. + +To run tests with coverage: + +. In the Testing panel, click the *Run all tests in this file* (▶) button. +. Click *Run Test With Coverage*. ++ +Alternatively, right-click the test suite file in the project explorer and select *Run MUnit Test with Coverage*. + +== Best Practices for MUnit Testing + +Follow these best practices to create maintainable and effective MUnit tests: + +* *Mock external dependencies*: Always mock database connections, HTTP requests to external APIs, and file system operations to keep tests fast and reliable. +* *Test one behavior per test case*: Each test should validate a single scenario (success path, specific error condition, and so on). +* *Use descriptive test names*: Names like `get-flight-by-valid-code-returns-200` clearly indicate what the test validates. +* *Maintain test data separately*: Consider storing sample payloads in separate files in `src/test/resources` for complex data structures. +* *Run tests frequently*: Execute tests after each significant change to catch issues early. +* *Aim for high coverage*: Target at least 80% code coverage, ensuring all critical paths are tested. +* *Test error scenarios*: Don't just test the happy path — validate that your error handlers work correctly too. + +== Troubleshoot Common MUnit Issues + +When creating and running MUnit tests, you may encounter issues related to test execution, mocking, or runtime configuration. These are some common problems and their solutions to help you resolve test failures. + +=== Test Timeout Errors + +If tests fail with timeout errors: + +* Increase the timeout value in your MUnit configuration. +* Check for infinite loops or blocking operations in your flows. +* Ensure mocked components return responses quickly. + +=== Mock Not Applied + +If mocks aren't being applied: + +* Verify the `doc:name` attribute in `with-attributes` exactly matches your component's name. +* Check that the processor type (`db:select`, `ee:transform`, and so on) is correct. +* Ensure the mock is defined in the `munit:behavior` section before execution. + +=== Assertion Failures + +When assertions fail: + +* Review the expected vs. actual values in the test output. +* Add Logger components to see intermediate payload transformations. +* Use debug mode to inspect the actual payload structure at the validation point. diff --git a/code-builder-home/modules/ROOT/pages/tut-flights-validate-transform-data.adoc b/code-builder-home/modules/ROOT/pages/tut-flights-validate-transform-data.adoc new file mode 100644 index 000000000..3c2815bfd --- /dev/null +++ b/code-builder-home/modules/ROOT/pages/tut-flights-validate-transform-data.adoc @@ -0,0 +1,445 @@ += Validate Input Parameters and Transform Flight Data +:imagesdir: ../assets/images +:page-pagination: + +When you scaffold an API specification into an implementation project, APIKit automatically validates incoming requests against your API specification. This validation includes: + +* *Path parameter formats*: If your API spec defines a pattern (such as `pattern: "^[A-Z]{2}\d+$"`), APIKit validates the format automatically. +* *Required vs. optional parameters*: APIKit ensures required parameters are present. +* *Data types*: APIKit validates that parameters match their specified types (string, integer, boolean, and so on). +* *Enum values*: If your spec defines allowed values, APIKit validates against that list. + +If a request doesn't match these rules, APIKit returns a `400 Bad Request` with an appropriate error message before your flow logic even executes. + +While APIKit handles format and structural validation, you need custom validation for: + +* *Business logic rules*: Validating that a resource exists in your system (for example, "Does this flight code exist in our database?"). +* *Cross-field validation*: Rules that depend on multiple parameters. +* *External system checks*: Validating against external APIs or services. +* *Database lookups*: Confirming that identifiers correspond to actual records. + +In this section, you add business logic validation to check whether a flight code exists in your database before attempting to query for it. This prevents unnecessary database calls and provides more meaningful error messages to API consumers. + +In the American Flights API, the example database stores flights with numeric IDs (1, 2, 3), but the API exposes flight codes like `AA123`, `AA456`, and `AA789`. You need to map these codes to database IDs and validate that the flight exists before querying. + +== Create the Flight Code to Database ID Mapping + +First, create a transform that stores the mapping of flight codes to database IDs. + +. In Anypoint Code Builder, open the `get:\flights\(flightId):american-flights-api-config` flow. +. If there's already a Transform Message component at the beginning of the flow, click it to open its properties. Otherwise, click *Add Component* (+) at the start of the flow and add *Core > Transform Message*. +. Click *Edit name* and change it to *Create Flight Code Map*. +. In the *General* tab, under *Target*, click *Add* (+) and select *Variable*. +. Click the edit icon next to `vars.NewVariable1` and set the name to `flightCodeMap`, then click *Apply*. +. In the *Inline Script* field, replace the content with this DataWeave script: ++ +[source,dataweave] +---- +%dw 2.0 +output application/java +--- +{ + "AA123": 1, + "AA234": 2, + "AA345": 3, + "AA456": 4, + "AA567": 5 +} +---- + +This creates a variable `vars.flightCodeMap` that maps flight codes to their corresponding database IDs. + +NOTE: In a production application, you would typically query the database directly rather than maintaining a hardcoded map. This tutorial uses a map to clearly demonstrate the validation logic without requiring additional database queries. + +== Look Up the Database Flight ID + +Now create a second transform to look up the flight code in the mapping you just created. + +. After the *Create Flight Code Map* transform, click *Add Component* (+). +. Select *Core > Transform Message*. +. Click *Edit name* and change it to *Lookup DB Flight ID*. +. In the *General* tab, under *Target*, click *Add* (+) and select *Variable*. +. Click the edit icon next to `vars.NewVariable1` and set the name to `dbFlightId`, then click *Apply*. +. In the *Inline Script* field for this variable, add: ++ +[source,dataweave] +---- +%dw 2.0 +output application/java +--- +vars.flightCodeMap[attributes.uriParams.flightId] +---- + +This script looks up the flight code from the request URL in the mapping created in the previous transform and returns the corresponding database ID. If the flight code isn't in the map, it returns `null`. + +NOTE: You cannot reference a variable in the same Transform Message where you're creating it. The variable only becomes available *after* the transform completes. By splitting the logic into two transforms, `vars.flightCodeMap` is available for use in the second transform. + +== Add a Choice Router to Validate Flight Existence + +Now add logic to check whether the flight code was found in the mapping. + +. After the *Lookup DB Flight ID* transform, click *Add Component* (+). +. Select *Core > Routers > Choice*. +. Click the *When* path inside the Choice router. +. In the *When* properties panel, under *Expression*, add this condition to check if the flight code wasn't found: ++ +[source,dataweave] +---- +#[vars.dbFlightId == null] +---- + +This expression evaluates to `true` when the flight code doesn't exist in the mapping. + +== Raise an Error for Unknown Flight Codes + +When a flight code isn't found, raise a custom error instead of proceeding with the query. + +. Inside the *When* path (where the condition is true), click *Add Component* (+). +. Select *Core > Error Handling > Raise Error*. +. In the *Raise Error* properties panel, configure: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Type* | `VALIDATION:FLIGHT_NOT_FOUND` +| *Description* | `#['Flight code ' ++ attributes.uriParams.flightId ++ ' not found in our system']` +|=== + +This creates a custom error type that you handle in the error handler, providing a meaningful message that includes the flight code the user attempted to look up. + +== Move the Database Query to the Otherwise Path + +The database query should only execute when the flight exists (when `vars.dbFlightId` is not null). + +. If you already have a *Database Select* operation after the Choice router, right-click it and select *Copy Component*. +. Click inside the *Otherwise* path of the Choice router (the path taken when the flight exists). +. Click *Add Component* (+) and select *Paste Component*. +. If you don't have an existing Database Select, add one inside the *Otherwise* path instead: +.. Click *Add Component* (+) and select *Connectors > Database > Select*. +.. Configure it with: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Name* | `Flight by ID` +| *Connection Config* | `Config` (your MySQL connection) +| *SQL Query Text* | `SELECT * FROM american WHERE ID = :flightId` +| *Input Parameters* | `#[{ 'flightId': vars.dbFlightId }]` +|=== + +. Delete the original Database Select component that was outside the Choice router, if it exists. + +Your flow should now look like this: + +. *Transform Message*: Create Flight Code Map (creates `vars.flightCodeMap`). +. *Transform Message*: Lookup DB Flight ID (creates `vars.dbFlightId` using `vars.flightCodeMap`). +. *Choice*: Check if Flight Exists. +.. *When* `vars.dbFlightId == null`: *Raise Error* (`VALIDATION:FLIGHT_NOT_FOUND`). +.. *Otherwise*: *Database Select* (Flight by ID). +. *Transform Message*: Transform Flight (converts the database result to JSON). + +== Add an Error Handler for Flight Not Found + +Now configure the error handler to return a proper 404 response when a flight isn't found. + +. In the canvas, open the `american-flights-api-main` flow (the main flow with the HTTP listener and error handler). +. In the *Error Handler* section at the bottom, click *Add Component* (+). +. Select *On Error Propagate*. +. In the *On Error Propagate* properties panel, set *Type* to `VALIDATION:FLIGHT_NOT_FOUND`. +. Inside this error handler, click *Add Component* (+) and add *Core > Logger*. +. In the *Logger* properties, set: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Level* | `WARN` +| *Message* | `#['Flight not found: ' ++ error.description]` +|=== + +This logs details about which flight was requested but not found, helping with debugging and monitoring. + +. After the Logger, click *Add Component* (+) and add *Core > Transform Message*. +. Configure the Transform Message: +.. In the *General* tab, under *Target > Payload*, set *Source* to *Inline Script*. +.. In the *Inline Script* field: ++ +[source,dataweave] +---- +%dw 2.0 +output application/json +--- +{ + message: error.description default "Flight not found", + flightId: attributes.uriParams.flightId +} +---- + +. Click *Add* (+) under *Target* and select *Variable*. +. Name the variable `httpStatus` and set its value to `404`. + +This returns a JSON response with a meaningful error message and the flight ID that was requested, along with a 404 HTTP status code. + +== Transform Data to Meet the API Contract + +When building an API implementation, it's essential that your responses match the structure defined in your API specification. While the database might store data in one format, your API contract defines how that data should be presented to consumers. DataWeave transformations bridge this gap by mapping database fields to the expected API response format. + +In this section, you create a DataWeave transformation that converts database query results into the JSON format specified in your American Flights API contract. + +=== Understand the Data Mapping Challenge + +Your MySQL database stores flight information with these fields: + +.Example database record +[source,json] +---- +{ + "ID": 1, + "code1": "rree", + "code2": "0001", + "airlineName": "American Airlines", + "toAirport": "LAX", + "fromAirport": "MUA", + "takeOffDate": "2016-01-20", + "price": 541, + "planeType": "Boeing 787", + "seatsAvailable": 0, + "totalSeats": 200 +} +---- + +Your API specification defines a different structure for the response: + +[source,json] +---- +{ + "ID": 1, + "code": "AA123", + "price": 499.99, + "departureDate": "2024-12-25T10:00:00", + "origin": "SFO", + "destination": "LAX", + "emptySeats": 45, + "plane": { + "type": "Boeing 737", + "totalSeats": 150 + } +} +---- + +Notice the transformation challenges: + +. *Field name changes*: Database fields have different names than API fields: +.. `fromAirport` → `origin` +.. `toAirport` → `destination` +.. `takeOffDate` → `departureDate` +.. `seatsAvailable` → `emptySeats` +. *Field combination*: `code1` and `code2` need to be combined into a single `code` field. +. *Nested object creation*: `planeType` and `totalSeats` (flat fields in the database) must become a nested `plane` object in the API response. +. *Fields to exclude*: `airlineName` is in the database but not needed in the API response. + +=== Step 1: Open the Transform Message Component + +In your implementation flow `get:\flights\{flightId}:american-flights-api-config`, you already have a Transform Message component after the Database Select operation. + +. In Anypoint Code Builder, locate the `get:\flights\{flightId}:american-flights-api-config` flow in your canvas. +. Click the *Transform Message* component named *Transform Flight* (after the *Flight by ID* database query). + +Currently, this transform just outputs `payload`, which passes through the raw database structure without transformation. + +=== Step 2: Define Input Metadata + +To help DataWeave understand the structure of your database results, define input metadata. + +. In the *Transform Message* properties panel, look at the left side showing *Input* (this represents `payload`, your database query results). +. Click the *Define metadata* link next to `payload: Unknown`. +. In the *Select metadata type* dialog, set: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Type ID* | `DatabaseFlightRecord` +| *Type* | *JSON* +|=== + +. Click *Create type* and provide this sample JSON structure (representing one database record): ++ +[source,json] +---- +{ + "ID": 1, + "code1": "rree", + "code2": "0001", + "airlineName": "American Airlines", + "toAirport": "LAX", + "fromAirport": "MUA", + "takeOffDate": "2016-01-20", + "price": 541, + "planeType": "Boeing 787", + "seatsAvailable": 0, + "totalSeats": 200 +} +---- +. Click *Save*. + +You should now see the input payload structure in the left panel, showing all available database fields. + +=== Step 3: Define Output Metadata + +Now define the expected API response format based on your specification. + +. In the *Transform Message* properties panel, look at the right side showing *Output* (this represents the API response). +. Click the *Define metadata* link next to the output. +. In the *Select metadata type* dialog, set: ++ +[%header,cols="20a,60a"] +|=== +| Field Name | Field Value + +| *Type ID* | `FlightResponse` +| *Type* | *JSON* +|=== + +. Click *Create type* and provide this sample JSON structure (from your API spec): ++ +[source,json] +---- +{ + "ID": 1, + "code": "AA123", + "price": 499.99, + "departureDate": "2024-12-25T10:00:00", + "origin": "SFO", + "destination": "LAX", + "emptySeats": 45, + "plane": { + "type": "Boeing 737", + "totalSeats": 150 + } +} +---- +. Click *Save*. + +The output panel now shows the expected response structure with the nested `plane` object. + +=== Step 4: Create the Field Mappings + +With both input and output metadata defined, you can now create the transformation using DataWeave's mapping features. + +[tabs] +==== +Use MuleSoft Vibes:: ++ +-- +. Open MuleSoft Vibes. +. Send this message: ++ +[source,command] +---- +In the get:\flights\(flightId):american-flights-api-config flow, open the Transform Flight component and add a transformation that maps the input metadata with the output metadata. For code, use code1 ++ code2. +---- ++ +NOTE: If you used a different flow or component name, ensure you specify it in the message so MuleSoft Vibes knows exactly which flow and components to modify. + +After MuleSoft Vibes finishes adding the transformation, confirm that the DataWeave script is similar to this: + +[source,dataweave] +---- +%dw 2.0 +output application/json +--- +{ + ID: payload[0].ID, + code: payload[0].code1 ++ payload[0].code2, + price: payload[0].price, + departureDate: payload[0].takeOffDate, + origin: payload[0].fromAirport, + destination: payload[0].toAirport, + emptySeats: payload[0].seatsAvailable, + plane: { + "type": payload[0].planeType, + totalSeats: payload[0].totalSeats + } +} +---- +-- + +Write the DataWeave Script Directly:: ++ +-- +You can write the complete DataWeave script in the *Script* view: + +. Click the *Script* tab in the Transform Message component. +. Replace the current content with: ++ +[source,dataweave] +---- +%dw 2.0 +output application/json +--- +{ + ID: payload[0].ID, + code: payload[0].code1 ++ payload[0].code2, + price: payload[0].price, + departureDate: payload[0].takeOffDate, + origin: payload[0].fromAirport, + destination: payload[0].toAirport, + emptySeats: payload[0].seatsAvailable, + plane: { + "type": payload[0].planeType, + totalSeats: payload[0].totalSeats + } +} +---- + +*Explanation:* + +* `code: payload[0].code1 ++ payload[0].code2` — concatenates `code1` and `code2` into a single `code` field. +* `departureDate: payload[0].takeOffDate` — renames the field from database to API format. +* `origin: payload[0].fromAirport` — maps `fromAirport` to `origin`. +* `destination: payload[0].toAirport` — maps `toAirport` to `destination`. +* `emptySeats: payload[0].seatsAvailable` — renames `seatsAvailable` to `emptySeats`. +* `plane: { ... }` — creates a nested object from flat database fields. +* `output application/json` — specifies the output format. +-- +==== + +=== Step 5: Test with Real Data + +Now test your transformation with actual database data. + +. Save your changes to the flow. +. Run the application locally using the *Run and Debug* panel. +. Once the application starts, use a REST client (such as Advanced REST Client) to call: ++ +[source,command] +---- +GET http://localhost:8081/api/flights/AA123 +---- +. Verify the response: +* Status code: `200 OK` +* Content-Type: `application/json` +* Body structure matches your API specification. +* The `plane` field is a nested object with `type` and `totalSeats`. +* Field names are correctly transformed from database format to API format. + +.Example expected response +[source,json] +---- +{ + "ID": 1, + "code": "rree0001", + "price": 541, + "departureDate": "2016-01-20", + "origin": "MUA", + "destination": "LAX", + "emptySeats": 0, + "plane": { + "type": "Boeing 787", + "totalSeats": 200 + } +} +---- diff --git a/code-builder-home/modules/ROOT/pages/tutorials.adoc b/code-builder-home/modules/ROOT/pages/tutorials.adoc index eec2c9fae..36f334011 100644 --- a/code-builder-home/modules/ROOT/pages/tutorials.adoc +++ b/code-builder-home/modules/ROOT/pages/tutorials.adoc @@ -32,6 +32,10 @@ Scaffold an API specification into an interface to implement, and sync changes t + Implement a GraphQL API that you publish to Exchange. -* xref:tut-slack-create-escalation-api.adoc[]: +* xref:tut-slack-create-escalation-api.adoc[]: + Create an integration that notifies you through email or Slack when a new case is created in Salesforce. + +* xref:tut-flights-api-tutorial.adoc[]: ++ +Design, implement, debug, test, deploy, and secure a database-backed REST API from start to finish, using the American Flights API as an example.