Skip to content

Mongrel.io User Documentation

Overview

Mongrel.io lets you create API endpoints that read from and write to multiple external APIs, transform data with JavaScript at every stage, and deliver a unified response — all without writing backend code. You can also forward data to downstream destinations such as webhooks, third-party APIs, or analytics services.

Each route you create becomes a live API endpoint with its own URL. A route is made up of five configurable sections:

  1. Name — Identify your route
  2. Authentication — Control who can access it
  3. Request — Define the incoming HTTP path and method
  4. Sources — Read from or write to external APIs, with optional transforms to shape request bodies
  5. Response — Transform the combined source data and configure the output format

You can also add Destinations to forward data to other services, each with their own optional transform to tailor the payload per recipient.


Getting Started

This walkthrough creates a simple route that reads user data from a public API, transforms it, and returns a clean JSON response. For examples of writing to external APIs, see Source Transform Function and Common Patterns.

Step 1: Create an API

After signing in at app.mongrel.io, create a new API from the dashboard. Each API has its own base URL (e.g. https://my-app.api.mongrel.io).

Step 2: Create a Route

Click + Create Route in the sidebar. You'll see the route editor with sections for Name, Authentication, Request, Sources, and Response.

Step 3: Configure the Route

Name: Enter a descriptive name (e.g. Getting Started). This appears in logs and the sidebar.

Request: Set the HTTP method to GET and enter a path like getting-started/hello. Your full endpoint URL will be shown (e.g. https://my-app.api.mongrel.io/getting-started/hello).

Source: Click + Add Source and configure it:

  • Name: usersApi (this is how you reference it in transforms)
  • Method: GET
  • URL: https://jsonplaceholder.typicode.com/users/1
  • Content-type: JSON

Response Transform: Click Edit on the Response Body and write a transform function:

function transform(data) {
    var user = data.sources.usersApi;
    return {
        name: user.name,
        email: user.email,
        city: user.address.city,
        company: user.company.name
    };
}

This function accesses the source data via data.sources.usersApi (matching the source name) and returns only the fields you want.

Step 4: Publish

Click Publish to make your route live. You can test it immediately:

curl https://my-app.api.mongrel.io/getting-started/hello

Response:

{
    "name": "Leanne Graham",
    "email": "Sincere@april.biz",
    "city": "Gwenborough",
    "company": "Romaguera-Crona"
}

Combining Multiple Sources

A key feature of Mongrel.io is interacting with multiple APIs in a single request. Here's an example that reads user details and their posts, then merges them into one response:

Source 1userDetails: - URL: https://jsonplaceholder.typicode.com/users/1 - Content-type: JSON

Source 2userPosts: - URL: https://jsonplaceholder.typicode.com/posts?userId=1 - Content-type: JSON

Response Transform:

function transform(data) {
    var user = data.sources.userDetails;
    var posts = data.sources.userPosts;
    var result = new Object();
    result.name = user.name;
    result.email = user.email;
    result.postCount = posts.length;
    result.latestPost = posts[0].title;
    return result;
}

This combines data from two independent API calls into a single response — no backend server required.


Name

  • Required: Yes
  • Description: The name of the route. Used to identify the route in logs, the sidebar, and publish events
  • Example: My Route

Route Authentication

Control how clients authenticate when accessing your API endpoint. Choose from three authentication methods.

None

No authentication required. Anyone with your endpoint URL can access it.

API Key

Require clients to include a valid API key with each request. The token should be passed in an X-Mongrel-Api-Key header.

JWT (JSON Web Token)

Validate requests using signed JSON Web Tokens.

JWKS URL

  • Required: Yes
  • Description: The URL where your identity provider publishes its JSON Web Key Set. Used to verify token signatures.
  • Example: https://auth.example.com/.well-known/jwks.json

Request

The Request section defines how external clients will call your API endpoint.

Path

  • Required: Yes
  • Description: The URL path where your endpoint will be accessible
  • Example: api/users or data/products/{id}
  • Supports Parameters: Use curly braces for path parameters (e.g., {id}, {userId})

Method

  • Required: Yes
  • Options: GET, PUT, POST, PATCH, DELETE
  • Description: The HTTP method your endpoint will accept

Content Type

  • Required: No
  • Options:
    • application/json
    • application/xml
    • text/csv
    • Empty (no body expected)
  • Description: The format of the incoming request body

Parse Options

See Parsing Options

CORS Options

Configure Cross-Origin Resource Sharing for browser-based clients.

Allowed Origins

  • Format: Comma separated list of URLs
  • Description: List of origins permitted to access this endpoint
  • Example: https://example.com,https://dev.example.com
  • Validation: Must be valid URLs

Allowed Headers

  • Format: Comma separated list of header names
  • Description: HTTP headers that can be used in requests
  • Example: Content-Type,Authorization
  • Validation: Must match pattern [\w-]+

Sources

Sources are external APIs that your route interacts with before transformation. With GET sources, your route reads data from the API. With POST, PUT, or PATCH sources, your route writes data to the API using a source transform to shape the request body. You can add multiple sources — both reading and writing — and access all of their responses in the response transform.

Name

  • Required: Yes
  • Description: Unique identifier for this source within your transformation function
  • Validation: Must be a valid JavaScript identifier
  • Usage: Access source data in transforms via data.sources.{name}
  • Example: userData, productInfo

Method

  • Required: Yes
  • Options: GET, POST, PUT, PATCH
  • Default: GET
  • Description: The HTTP method used when calling this source API. Use GET to read data, or POST, PUT, PATCH to write data

Note: When using POST, PUT, or PATCH, you must provide a source transform function that shapes the request body to send. GET sources cannot have a transform function.

URL

  • Required: Yes
  • Description: The full URL of the external API to call
  • Example: https://api.example.com/users
  • Supports Variables: Yes — see Using Variables in URLs

Content Type

  • Required: Yes
  • Options:
    • JSON (application/json)
    • XML (application/xml)
    • CSV (text/csv)
  • Description: The format of data exchanged with the source API. For GET requests, this is the response format. For POST, PUT, and PATCH, this applies to both the request body sent and the response received

Authentication

See Authentication Options

Cache Options

Enable caching to reduce the number of calls to a source API.

  • Enabled: Boolean — turn caching on or off
  • TTL (Time to Live): Number — how long (in seconds) to cache the source response before making a new call

When caching is enabled, repeated calls to the same source will return the cached response until the TTL expires.

Source Transform Function

For POST, PUT, and PATCH sources, you must provide a transform function that returns the request body to send to the source API. This is how your route writes data to external APIs. The function receives the same data object as the response transform, giving you access to the incoming request data and responses from previously executed sources.

Example: Create a record in an external API

function transform(data) {
    return {
        name: data.request.body.name,
        email: data.request.body.email,
        createdBy: "mongrel-route"
    };
}

Example: Update an external API using data from another source

function transform(data) {
    var user = data.sources.userLookup;
    return {
        userId: user.id,
        accountId: user.accountId,
        action: data.request.body.action
    };
}

The response from a write source is available in data.sources.{name} just like a read source, so you can use the API's response (e.g. a created record ID) in your response transform or in subsequent sources.

Test Source

Each source has a Test Source button that lets you make a test call to the configured API and see the response. This is useful for:

  • Verifying the URL and authentication are correct
  • Checking the response format and structure
  • For write sources (POST, PUT, PATCH), verifying the request body is shaped correctly
  • Understanding the data before writing transforms

Parse Options

See Parsing Options


Transform and Response

The Response section defines how your route's output will be returned to the caller. The core of this section is the transform function, where you combine and reshape data from all source responses — whether those sources were reading data or writing it — into your desired output.

Transform Function

Function Requirements

  • Parameters: Must accept exactly one parameter (typically named data)
  • Return: Must return a value
  • Language: JavaScript (ECMAScript 2020)
  • Validation: Code is validated for correct syntax and structure
  • Supports: Function declarations, function expressions, and arrow functions

Input Data Structure

Your function receives a data object with the following structure:

{
  request: {
    body: {},           // Parsed request body (if any)
    path: {},           // Path parameters as key-value pairs
    query: {},          // Query parameters (values are arrays)
    headers: {}         // Request headers (values are arrays)
  },
  sources: {
    sourceName: {},     // Response data from each source by name
    anotherSource: {}
  },
  item: {}              // Present when split is enabled
}

Transform Debugger

The transform editor includes a Test Function button that opens the transform debugger. This tool lets you:

  • Provide sample input data
  • Execute the transform function
  • See the output or any errors

Use it to iterate on your transform logic before publishing.

Accessing Data from Different Formats

The way you access data in your transformation function depends on the content type of your sources.

JSON Source Data

JSON sources are parsed into JavaScript objects, allowing direct property access:

function(data) {
  const dev = data.sources.devApi.developer;
  return {
    name: dev.name,
    email: dev.email
  };
}

XML Source Data

XML sources are converted to JavaScript objects. Element attributes use the configured prefix (default @_), and text content uses the text node name:

function(data) {
  const devs = data.sources.standupApi.standup_notes.developer;
  return devs.map(dev => ({
    id: dev["@_id"],
    name: dev.name,
    blocked: dev.blockers["@_status"] === "ongoing"
  }));
}

CSV Source Data

CSV sources are parsed as arrays of objects (when objectMode: true) or arrays of arrays:

function(data) {
  const devs = data.sources.devCsv;
  return devs.map(dev => ({
    developerId: parseInt(dev.dev_id),
    name: dev.name,
    language: dev.language
  }));
}

Function Examples

Simple Pass-Through

function transform(data) {
  return data.sources.myApi;
}

Combining Multiple Sources

function transform(data) {
  return {
    user: data.sources.userApi,
    orders: data.sources.orderApi,
    timestamp: Date.now()
  };
}

Filtering with Query Parameters

function transform(data) {
  const users = data.sources.userList;
  const filter = data.request.query.status?.[0] || 'active';

  return users
    .filter(user => user.status === filter)
    .map(user => ({
      id: user.id,
      fullName: `${user.firstName} ${user.lastName}`,
      email: user.email
    }));
}

Response Code

  • Required: Yes
  • Options: 200, 201, 202
  • Description: HTTP status code for successful responses

Response Content Type

  • Required: Yes
  • Options:
    • application/json
    • application/xml
    • text/csv
  • Description: Format for the response body

Response Cache Options

Enable caching on the response to reduce processing for repeated identical requests.

  • Enabled: Boolean — turn caching on or off
  • TTL (Time to Live): Number — how long (in seconds) to cache the response

When enabled, the full response (after all source calls and transformation) is cached. Subsequent identical requests return the cached result until the TTL expires.

Write Options

See Writing Options


Destinations

Define zero or more destinations to forward your data to after the response is generated.

Name

  • Required: Yes
  • Description: Identifier for this destination
  • Validation: Must be a valid JavaScript identifier
  • Example: webhook, analyticsApi

URL

  • Required: Yes
  • Description: Target endpoint URL
  • Example: https://webhook.example.com/data
  • Supports Variables: Yes — see Using Variables in URLs

Content Type

  • Required: Yes
  • Options: application/json, application/xml, text/csv
  • Description: Format for data sent to this destination

Method

  • Required: Yes
  • Options: GET, PUT, PATCH, POST, DELETE
  • Description: HTTP method to use when sending to destination

Split

  • Type: Boolean
  • Default: false
  • Description: When true, if the response data is an array, each item is sent as a separate HTTP request to this destination

Authentication

See Authentication Options

Write Options

See Writing Options

Destination Transform Function

  • Required: No
  • Available for: PUT, PATCH, POST, DELETE methods (not GET)
  • Description: A JavaScript function that transforms the response data before it is sent to this destination. This enables the Backend for Frontend (BFF) pattern where each destination can receive a differently shaped payload.

When no transform function is provided, the destination receives the response data as-is.

Input Data Structure

The destination transform function receives a data object with the following structure:

{
  request: {
    body: {},           // Parsed request body (if any)
    path: {},           // Path parameters
    query: {},          // Query parameters
    headers: {}         // Request headers
  },
  sources: {
    sourceName: {},     // Response data from each source by name
  },
  response: {}          // The response transform result
}

When split mode is enabled, data.response contains the individual array item being processed, not the full array.

Example: Filter Fields for a Webhook

function transform(data) {
  return {
    email: data.response.email,
    event: "user_updated",
    timestamp: Date.now()
  };
}

Example: Reshape for a Third-Party API

function transform(data) {
  const orders = Array.isArray(data.response) ? data.response : [data.response];
  return {
    total: orders.length,
    revenue: orders.reduce((sum, o) => sum + o.amount, 0),
    currency: orders[0]?.currency || "USD"
  };
}

Authentication Options

Configure how to authenticate with an external source or destination.

Type: BASIC

HTTP Basic Authentication - username: Username for authentication - password: Password for authentication

Type: HEADER_KEY

API key in request header - keyName: Name of the header (e.g., X-API-Key) - apiKey: The API key value

Type: QUERY_KEY

API key in query parameter - keyName: Name of the query parameter (e.g., api_key) - apiKey: The API key value

Type: BEARER_TOKEN

Bearer token authentication - token: The bearer token value

Type: OIDC

OpenID Connect authentication - tokenUrl: OAuth token endpoint URL - clientId: OAuth client ID - clientSecret: OAuth client secret - scope: Requested OAuth scopes - token (optional): Cached token (managed automatically)


Parsing Options

Parse options vary based on the selected content type:

JSON Parse Options

Currently no specific parse options are required for JSON.

XML Parse Options

Attribute Handling

  • ignoreAttributes: When enabled, all element attributes are excluded from parsing. Set to true to treat everything as tags only, or false to include attributes in the output.

  • allowBooleanAttributes: Enables parsing of attributes that have no value assignment (e.g., <input checked>). When set to true, these attributes appear in the output with a value of true. Must be used with ignoreAttributes: false.

  • attributeNamePrefix: String prepended to all attribute names to distinguish them from child elements in the output object. Common value is @_. Only applies when ignoreAttributes is false.

  • attributesGroupName: When specified, collects all attributes of an element under a single property with this name. Helps separate attributes from child elements. Requires ignoreAttributes: false.

Text Content

  • textNodeName: Specifies the property name used for the text content of elements. Useful when an element has both text and attributes or child elements. Default varies based on other settings.

  • alwaysCreateTextNode: Forces creation of a dedicated text node property even for simple text-only elements. When false, simple text is assigned directly to the tag property.

  • trimValues: Removes leading and trailing whitespace from all text values and attribute values during parsing.

Special Content Types

  • cdataPropName: Property name used to identify CDATA sections in the output. If not specified, CDATA content is merged with regular text content.

  • commentPropName: Property name for preserving XML comments in the parsed output. Comments are typically ignored unless this is set. Works best with preserveOrder: true.

Structure and Order

  • preserveOrder: Maintains the exact order of elements as they appear in the XML document. When enabled, the output structure changes to preserve sequence, which is especially important for mixed content.

  • arrayPaths: Comma-separated list of element paths that should always be parsed as arrays, even when only one element exists. Helpful for consistent data structures.

Namespaces and Entities

  • removeNsPrefix: Strips namespace prefixes from element and attribute names (e.g., converts ns:tagName to tagName).

  • processEntities: Controls whether XML entities (like &lt;, &gt;, &amp;) and DOCTYPE entities are decoded during parsing. Enabled by default. Disable for better performance if your XML doesn't contain entities.

  • htmlEntities: Enables recognition and parsing of HTML-specific entities beyond standard XML entities.

Processing Control

  • stopNodes: Comma-separated list of element paths where parsing should halt, leaving the content as raw text. Useful for elements like <script> or <pre> where you want to preserve content exactly. Can use wildcards (e.g., *.script).

  • ignorePiTags: When enabled, skips processing instruction tags (e.g., <?xml-stylesheet ?>).

  • ignoreDeclaration: Excludes the XML declaration (e.g., <?xml version="1.0"?>) from the parsed output.

  • unpairedTags: Comma-separated list of tag names that are self-closing and don't require a closing tag (e.g., HTML tags like br, img, hr).

CSV Parse Options

Data Format

  • objectMode: Controls the output format of parsed rows. When true (default), each row is returned as an object with column names as keys. When false, rows are returned as arrays of values.

  • delimiter: The character used to separate columns in your CSV file. Defaults to comma (,). Change this if your file uses alternative separators like semicolon (;) or tab (\t). Must be a single character.

  • headers: Determines how column headers are handled. Set to true to use the first row as headers. Provide a string array to manually define header names. Set to false (default) if your CSV has no headers. Headers must be unique or parsing will fail.

  • renameHeaders: When enabled, replaces the first row of the CSV with custom headers specified in the headers option. Only applies when headers is provided as an array. Use this when you want to discard the original header row.

Quote and Escape Handling

  • quote: The character used to wrap fields containing special characters like delimiters or line breaks. Defaults to double quote ("). Set to empty string to disable quote handling entirely.

  • escape: Character used to include a quote character within a quoted field. Defaults to double quote (").

Whitespace Management

  • trim: Removes whitespace from both the beginning and end of all column values.

  • ltrim: Strips whitespace only from the left (beginning) of column values.

  • rtrim: Removes whitespace only from the right (end) of column values.

Row Filtering

  • ignoreEmpty: Skips rows that are completely empty or contain only whitespace and delimiters.

  • comment: Single character that marks a line as a comment (e.g., #). Lines starting with this character are ignored during parsing.

  • maxRows: Limits parsing to a specific number of rows. Set to 0 or leave unset for no limit.

  • skipRows: Number of data rows to skip after headers are processed.

  • skipLines: Number of raw lines to skip from the beginning of the file before parsing starts.

Column Handling

  • discardUnmappedColumns: When enabled, any columns beyond the number of defined headers are silently dropped.

  • strictColumnHandling: Treats rows with column count mismatches as invalid rather than throwing errors.

Encoding

  • encoding: Character encoding of the CSV file. Defaults to utf8. Change to utf16le, ascii, or iso-8859-1 if your file uses a different encoding.

Writing Options

Write options vary based on the selected content type:

JSON Write Options

  • includeFields: Comma-separated list of fields to include in output
  • indent: Number of spaces for JSON formatting (omit for compact JSON)

XML Write Options

Structure and Formatting

  • format: Enables pretty-printing of the XML output with proper indentation and line breaks. When false, produces compact single-line XML.

  • indentBy: Defines the string used for each indentation level when formatting is enabled. Common values include two spaces or a tab character. Only applies when format is true.

  • arrayNodeName: Specifies the tag name to use when building XML from an array at the root level.

  • preserveOrder: Maintains the exact sequence of elements as they exist in the JavaScript object. Should match the parser setting if round-tripping data.

Attribute Control

  • ignoreAttributes: When true, skips all attributes during XML generation. Can also accept an array of attribute names to selectively exclude.

  • attributeNamePrefix: String that identifies attribute properties in the JavaScript object. Must match the parser setting for consistent round-tripping.

  • attributesGroupName: Property name that contains all attributes for an element grouped together.

  • suppressBooleanAttributes: When enabled, attributes with boolean true values are written without values (e.g., <input checked>).

Text Content

  • textNodeName: Identifies which property contains the text value of an element. Typically "#text".

Special Content Handling

  • cdataPropName: Property name that marks content to be wrapped in CDATA sections.

  • commentPropName: Property name identifying XML comments in the data structure.

Entity Processing

  • processEntities: Controls conversion of special characters to XML entities during output. When true (default), characters like <, >, and & are encoded.

Empty and Self-Closing Tags

  • suppressEmptyNode: When enabled, elements with no content are rendered as self-closing tags.

  • unpairedTags: Comma-separated list of tag names that should be rendered as self-closing tags.

  • suppressUnpairedNode: Controls whether unpaired tags include a closing slash.

Advanced Options

  • oneListGroup: When enabled, wraps array items under a parent container tag.

  • stopNodes: Comma-separated list of element paths where processing should stop, preserving the content as raw text.

CSV Write Options

Field and Row Separators

  • delimiter: Character used to separate columns in the output. Defaults to comma (,).

  • rowDelimiter: Character sequence used to separate rows. Defaults to newline (\n).

  • includeEndRowDelimiter: When enabled, adds a row delimiter after the final row of data.

Quote and Escape Control

  • quote: Character used to wrap field values containing special characters. Defaults to double quote (").

  • escape: Character used to escape quote characters within quoted fields.

  • quoteColumns: Controls which data columns get quoted. Set to true to quote all columns, or use selective options.

  • quoteHeaders: Determines which header values are quoted.

Header Configuration

  • headers: Controls header row generation. Set to true to auto-detect headers from data.

  • writeHeaders: When false, suppresses the header row entirely.

  • alwaysWriteHeaders: Forces header row output even when no data rows are written.

  • forceHeaders: Comma-separated string of header names to force in the output.

Column-Level Quoting

  • quotedColumns: Comma-separated string listing specific column names that should always be quoted.

  • quotedHeaders: Comma-separated string of header names that should be quoted.

Special Options

  • writeBOM: When enabled, writes a UTF-8 Byte Order Mark as the first character of the output.

Tools

Mongrel.io provides several tools to help you build, test, and monitor your routes.

Source Tester

Each source configuration includes a Test Source button. Click it to make a live request to the source API and see the response. This lets you verify the URL, authentication, request body (for write sources), and response format before publishing.

Transform Debugger

The transform editor includes a Test Function button that opens the debugger. You can provide sample input data, execute the function, and see the result or errors. Use this to iterate on your transform logic.

Request Logs

The Request Logs view (accessible from the sidebar) shows recent requests to your published routes, including:

  • Request timestamp
  • HTTP method and path
  • Response status code
  • Execution time
  • Any errors that occurred

Use request logs to monitor your routes and debug issues.

Publish Events

The Publish Events view (accessible from the sidebar) shows a history of publish and unpublish actions for your routes, including:

  • When the route was published
  • The version that was published
  • Whether the publish succeeded or failed

Common Patterns

Using Variables in URLs

Both Source URLs and Destination URLs support template variables, allowing you to dynamically construct URLs based on incoming request data and data from other sources.

Template Syntax

Variables are inserted using JavaScript template literal syntax: ${expression}

Available Data in URLs

You can access the same data object available in transformation functions:

{
  request: {
    body: {},           // Parsed request body
    path: {},           // Path parameters as key-value pairs
    query: {},          // Query parameters (values are arrays)
    headers: {}         // Request headers (values are arrays)
  },
  sources: {
    sourceName: {}      // Response data from previously executed sources
  }
}

Note: Sources are automatically executed in the correct order based on their dependencies. If one source references another in its URL or transform, the system ensures the referenced source is executed first.

Examples

Using Path Parameters

Request path: /api/users/{userId}/orders/{orderId}

Source URL:

https://api.example.com/users/${data.request.path.userId}

Using Query Parameters

Request: /api/search?status=active&limit=10

Source URL:

https://api.example.com/items?status=${data.request.query.status[0]}&max=${data.request.query.limit[0]}

Remember that query parameter values are arrays, so use [0] to get the first value.

Using Request Headers

Source URL:

https://api.example.com/data?tenant=${data.request.headers['x-tenant-id'][0]}

Using Request Body Fields

Source URL:

https://api.example.com/customers/${data.request.body.customerId}/orders?type=${data.request.body.orderType}

Using Data from Other Sources

You can reference data from other sources to create API call chains:

  1. Source 1 — Name: userApi, URL: https://api.example.com/users/${data.request.path.userId}
  2. Source 2 — Name: ordersApi, URL: https://api.example.com/accounts/${data.sources.userApi.accountId}/orders

The system detects this dependency and ensures userApi executes before ordersApi.

Complex Expressions

https://api.example.com/items?limit=${data.request.query.limit ? data.request.query.limit[0] : '10'}

Best Practices

  • URL Encode Values: If your variables might contain special characters, consider handling encoding in your transformation function
  • Validate Required Fields: Ensure path parameters and required query parameters are present before they're used in URLs
  • Use Fallbacks: Provide default values for optional parameters: ${data.request.query.page?.[0] || '1'}
  • Source Dependencies: The system automatically resolves source dependencies based on URL references, so you can define sources in any order

Using Path Parameters

// Request path: /users/{userId}/orders/{orderId}
function(data) {
  const userId = data.request.path.userId;
  const orderId = data.request.path.orderId;

  return {
    user: userId,
    order: orderId,
    details: data.sources.orderApi
  };
}

Accessing Query Parameters

// Query parameters come as arrays
function(data) {
  const limit = parseInt(data.request.query.limit?.[0] || '10');
  const page = parseInt(data.request.query.page?.[0] || '1');

  return data.sources.items.slice((page - 1) * limit, page * limit);
}

Working with Split Mode

// Transformation returns array
function(data) {
  return data.sources.users.map(user => ({
    id: user.id,
    email: user.email
  }));
}
// With split=true on destination, each user object
// is sent as a separate HTTP request

Writing to External APIs

Sources can write data to external APIs using POST, PUT, or PATCH methods. The source transform shapes the request body, and the API's response is available alongside read sources in your response transform.

Example: Create a record and return the result

A route with request method POST and two sources:

  • Source 1lookupUser (GET): https://api.example.com/users/${data.request.body.userId}
  • Source 2createOrder (POST): https://api.example.com/orders

Source transform for createOrder:

function transform(data) {
    var user = data.sources.lookupUser;
    return {
        customerId: user.customerId,
        items: data.request.body.items,
        shippingAddress: user.defaultAddress
    };
}

Response transform:

function transform(data) {
    return {
        orderId: data.sources.createOrder.id,
        status: data.sources.createOrder.status,
        customer: data.sources.lookupUser.name
    };
}

This pattern reads data from one API, uses it to write to another, and returns a combined response.

Error Handling

Errors in transformation functions or source API calls will result in error responses. Ensure your transformation handles missing or unexpected data gracefully:

function(data) {
  const users = data.sources.userApi?.users || [];

  return users.map(user => ({
    id: user.id,
    name: user.name || 'Unknown',
    email: user.email || 'no-email@example.com'
  }));
}

Troubleshooting

Route won't publish

If clicking Publish does nothing, check for validation errors:

  • Invalid JavaScript syntax: Open the transform editor and check for syntax errors. The editor validates your code and shows errors at the bottom.
  • Missing required fields: Ensure all sources have a name, URL, and content type. Ensure the request path is set.
  • Source transform required: If a source uses POST, PUT, or PATCH, it must have a transform function.

Source returns unexpected data

  • Use the Test Source button to see the raw response from the source API
  • Check the content type matches the actual response format (e.g., don't set JSON for an XML response)
  • Verify the URL is correct and the API is accessible
  • For write sources (POST, PUT, PATCH), check that the source transform is producing the correct request body

Transform function errors

  • Use the Test Function button in the transform editor to debug
  • Check you're accessing source data with the correct name: data.sources.yourSourceName
  • Ensure your function has a return statement
  • Remember that query parameters and headers are arrays — use [0] to access the first value

Cached data is stale

If your route returns stale data, check cache settings:

  • Source cache: Disable or reduce TTL on individual source cache options
  • Response cache: Disable or reduce TTL on the response cache options
  • Unpublish and republish the route to clear caches