MuleSoft Building REST APIs

Building a REST API in MuleSoft means creating an application that listens for HTTP requests, processes the data, and returns structured responses. MuleSoft makes this straightforward with the HTTP Connector and the APIkit Router. This topic walks through building a complete CRUD REST API for managing products.

What Is a REST API

REST (Representational State Transfer) is the most common style for building APIs. REST APIs use standard HTTP methods to perform actions on resources:

  • GET: Read or retrieve data
  • POST: Create new data
  • PUT: Replace existing data completely
  • PATCH: Update part of existing data
  • DELETE: Remove data

REST API Resource Map for Products

HTTP Method | Endpoint              | Action
------------|----------------------|-----------------------------
GET         | /products            | Get all products
GET         | /products/{id}       | Get one product by ID
POST        | /products            | Create a new product
PUT         | /products/{id}       | Replace a product
PATCH       | /products/{id}       | Partially update a product
DELETE      | /products/{id}       | Delete a product

HTTP Status Codes for REST APIs

Every REST response includes an HTTP status code that tells the caller whether the request succeeded or failed.

Status Code Reference

Code | Meaning
-----|-------------------------------
200  | OK — request succeeded
201  | Created — new record created
204  | No Content — success, nothing to return (used for DELETE)
400  | Bad Request — invalid input from client
401  | Unauthorized — authentication required
403  | Forbidden — authenticated but not permitted
404  | Not Found — resource does not exist
409  | Conflict — duplicate or state conflict
422  | Unprocessable Entity — validation failed
500  | Internal Server Error — server-side problem
503  | Service Unavailable — dependency is down

Building the Product API in MuleSoft

Start by creating a new Mule project in Anypoint Studio. The project will have one file with multiple flows — one flow per endpoint.

Flow Structure for Product API

products-api.xml:
  |
  +-- getAllProductsFlow
  |     [HTTP Listener: GET /products]
  |     [Database: SELECT * FROM products]
  |     [Transform: rows to JSON array]
  |
  +-- getProductByIdFlow
  |     [HTTP Listener: GET /products/{id}]
  |     [Database: SELECT * FROM products WHERE id = #[attributes.uriParams.id]]
  |     [Choice: found? 200 : 404]
  |
  +-- createProductFlow
  |     [HTTP Listener: POST /products]
  |     [Validate: check required fields]
  |     [Database: INSERT INTO products...]
  |     [Set HTTP Status: 201]
  |
  +-- updateProductFlow
  |     [HTTP Listener: PUT /products/{id}]
  |     [Database: UPDATE products SET... WHERE id=...]
  |     [Choice: updated? 200 : 404]
  |
  +-- deleteProductFlow
        [HTTP Listener: DELETE /products/{id}]
        [Database: DELETE FROM products WHERE id=...]
        [Set HTTP Status: 204]
        [Set Payload: empty]

Configuring the HTTP Listener for Each Method

Each flow needs its own HTTP Listener. All listeners share the same connector configuration (host and port) but differ in path and allowed methods.

HTTP Listener Properties for Each Endpoint

getAllProductsFlow Listener:
  Config: HTTP_Listener_Config (0.0.0.0:8081)
  Path:   /products
  Method: GET

createProductFlow Listener:
  Config: HTTP_Listener_Config (same config, shared)
  Path:   /products
  Method: POST

getProductByIdFlow Listener:
  Config: HTTP_Listener_Config (same config)
  Path:   /products/{id}     ← URI parameter
  Method: GET

updateProductFlow Listener:
  Config: HTTP_Listener_Config (same config)
  Path:   /products/{id}
  Method: PUT

deleteProductFlow Listener:
  Config: HTTP_Listener_Config (same config)
  Path:   /products/{id}
  Method: DELETE

Reading URI Parameters

When a path contains {id}, MuleSoft captures whatever the caller puts there. Access it using attributes.uriParams.id.

Request: GET /products/PROD-007

In the flow:
attributes.uriParams.id = "PROD-007"

Database query:
SELECT * FROM products WHERE id = '#[attributes.uriParams.id]'
→ SELECT * FROM products WHERE id = 'PROD-007'

Reading Query Parameters

Query parameters appear after the question mark in a URL. Access them with attributes.queryParams.paramName.

Request: GET /products?category=electronics&maxPrice=500

In the flow:
attributes.queryParams.category  = "electronics"
attributes.queryParams.maxPrice  = "500"

DataWeave to build the WHERE clause:
"SELECT * FROM products WHERE category = '" ++ 
attributes.queryParams.category ++ 
"' AND price <= " ++ 
attributes.queryParams.maxPrice

Reading the Request Body

For POST and PUT requests, the request body becomes the payload. Parse it with a Transform Message if needed.

POST /products
Content-Type: application/json
Body:
{
  "name": "Wireless Mouse",
  "category": "electronics",
  "price": 29.99,
  "stock": 150
}

In the flow:
payload.name     = "Wireless Mouse"
payload.category = "electronics"
payload.price    = 29.99
payload.stock    = 150

Database Insert:
INSERT INTO products (name, category, price, stock)
VALUES (#[payload.name], #[payload.category], #[payload.price], #[payload.stock])

Setting the HTTP Response Status Code

Use the HTTP Response settings or the Set Variable component to set the status code. In the HTTP Listener's response section, reference a variable for the status code.

For a successful POST (create):
  [Set Variable: name="httpStatus", value=201]
  [HTTP Listener Response: status=#[vars.httpStatus]]

For a 404 Not Found:
  [Set Variable: name="httpStatus", value=404]
  [Set Payload: {"error": "Product not found"}]

Complete GET by ID Flow Example

Flow: getProductByIdFlow

[HTTP Listener: GET /products/{id}]
      |
      v
[Database: SELECT * FROM products WHERE id = '#[attributes.uriParams.id]']
      |
      v
[Choice Router]
  Condition: sizeOf(payload) > 0
  |
  +-- TRUE:
  |     [Transform: rows[0] to JSON object]
  |     [Set Variable: httpStatus = 200]
  |
  +-- FALSE (no record found):
        [Set Payload: {"error": "Product not found"}]
        [Set Variable: httpStatus = 404]
      |
      v
[HTTP Listener Response: status=#[vars.httpStatus], body=#[payload]]

Input Validation

Always validate request data before processing. Use a Choice Router to check required fields and return a 400 error with a descriptive message if validation fails.

[Choice Router: validate POST body]
  Condition: payload.name == null or payload.price == null
  |
  +-- TRUE (invalid):
  |     [Set Payload: {"error": "name and price are required"}]
  |     [Set Variable: httpStatus = 400]
  |     (skip database, go to response)
  |
  +-- FALSE (valid):
        [Database Insert]
        [Set Variable: httpStatus = 201]

Testing the API with Postman

Run the Mule application locally and open Postman. Create a collection named "Product API" and add requests for each endpoint. Test each HTTP method with valid and invalid data to verify the correct status codes and response bodies are returned. Always test error scenarios like missing fields, invalid IDs, and duplicate records.

Leave a Comment

Your email address will not be published. Required fields are marked *