Skip to content

Martini HTTP Functions

Overview

Martini HTTP Functions let your services and workflows send outbound HTTP and SOAP requests, write ad hoc HTTP responses, and inspect request/response headers — without writing low-level HTTP client code.

What You Will Learn

  • How to send an HTTP request with sendRequest and choose the right returnAs/responseType combination
  • How to reuse a previously cached response for sendRequest calls with cacheName, cacheMode, and cacheKey
  • How to send a SOAP request with sendSoapRequest
  • How to write an ad hoc HTTP response with writeResponse and signal $requestHandled
  • How to read individual headers from an HTTP Filter trigger's request/response with getRequestHeader/getResponseHeader
  • How to check whether a request is authenticated with IdentityMethods.isAuthenticated

When To Use This

Use Martini HTTP Functions when you need to:

  • Call an external REST API from a workflow or service and map its response into a data model
  • Reuse a successful response from a rate-limited third-party API instead of resending an idempotent request, such as a GET
  • Call an external SOAP web service without hand-building the SOAP envelope
  • Write a custom HTTP response body, status code, and headers for an ad hoc REST service, instead of relying on the default response mapping
  • Read a specific header from the request or response of an HTTP Filter trigger, for example to implement custom authentication
  • Check whether the current request is authenticated before continuing a workflow or service

Prerequisites

Sending HTTP Requests with sendRequest

sendRequest sends a RESTful HTTP request and returns the response, replacing the deprecated HttpMethods.http.

Getting Started

Using a Function Node or a Function Step, invoke sendRequest, providing at minimum a request with the target method and url:

1
2
3
4
5
sendRequest(
    request: [method: 'GET', url: 'https://api.example.com/customers/42'],
    returnAs: 'Data Model Property',
    responseType: 'JSON'
)

Expected result: the JSON response body is deserialized directly onto a data model property in your workflow or service.

Parameters

Property Type Description
request io.toro.martini.http.Request Data Model Details of the HTTP request, including method, URL, headers, and body. Multipart file uploads are represented in the request body using the io.toro.martini.http.MultipartFile data model — not a generic data model.
auth io.toro.martini.http.Auth Data Model Authentication information for the request.
returnAs String Determines how the response body is returned. See returnAs values below.
responseType String Determines how the response body is parsed before being returned. See responseType values below.
throwHttpExceptions Boolean Whether to throw an exception for 5xx HTTP responses.
cacheName String Name of a cache declared in the owning package's caches.conf. When blank, no caching is attempted and sendRequest behaves exactly as it did without caching. See Reusing Cached Responses below.
cacheMode String How the named cache is used: eager or fallback. Required whenever cacheName is provided; an IllegalArgumentException is thrown if cacheName is set and cacheMode is missing or unrecognized. See cacheMode values below.
cacheKey String A custom cache key expression. When blank, the key is derived by default from the request's HTTP method, URL, and query parameters.
trackable io.toro.martini.tracker.Trackable Data Model Tracking options for the call, recorded in Martini's Tracker.

returnAs values

Value Use case
InputStream Stream the raw response body, for example when forwarding a large payload or binary file without buffering it fully in memory.
String Return the raw response body as text, useful when the caller wants to inspect or further parse the payload itself.
byte[] Return the raw response body as a byte array, useful for binary payloads that are not streamed.
Data Model Property Deserialize the response body directly into a data model property on the workflow/service, based on responseType. This is the current preferred option for structured (JSON/XML) responses.

responseType values

Value Use case
JSON The response body is JSON and should be parsed as such when returnAs is Data Model Property.
XML The response body is XML and should be parsed as such when returnAs is Data Model Property.
Auto-detect Martini inspects the response's Content-Type header to determine whether to parse the body as JSON or XML. Use this when the target endpoint may return either format.

cacheMode values

Value Behavior
eager Return the cached response if one is present. On a cache miss, send the HTTP request and, if the response is 2xx, cache it under the resolved cache key.
fallback Send the HTTP request first. If the response has an HTTP status code of 429 (Too Many Requests), return a cached response for the resolved cache key if one exists.

Return Value

Returns a io.toro.martini.http.Response data model with the server's response data.

Reusing Cached Responses with sendRequest

sendRequest can optionally reuse a previously cached response through a named cache declared in the owning package's caches.conf, instead of always calling the target web service. This is primarily intended for idempotent requests, such as GET, against rate-limited third-party APIs where a recent successful response can safely be reused.

Caching is only attempted when cacheName is provided:

  • Only responses with a 2xx status code are cached.
  • The full HTTP response is cached — not only the response body — so a cache hit returns the same headers, status code, and body as the original response.
  • Caching is always skipped when returnAs is InputStream, because the response body can't be replayed from the cache. sendRequest does not buffer or otherwise make InputStream responses cacheable.
  • If the owning package has no cache configured under the given cacheName, caching is skipped, a warning is logged, and the request is sent as if no cacheName had been provided.
  • Cache entry expiry (TTL) is controlled by the named cache's caches.conf configuration (for example, expireAfterWrite/expireAfterAccess).
  • Manual invalidation is handled through Cache Functions, such as cacheInvalidate and cacheInvalidatePattern. sendRequest has no separate expiry or invalidation settings of its own.

Prerequisites for Caching

Before calling sendRequest with cacheName, configure a named cache in the caches.conf file of the package that calls sendRequest.

Cache Key Derivation

By default, the cache key includes only the request's HTTP method, URL, and query parameters. Headers (including authorization) and the request body are not included. If the response varies by a header, authenticated identity, or body, do not use the default key; provide a cacheKey that includes the relevant safe tenant or request context.

Eager Mode Example

Use eager mode to avoid resending a request when a cached response is already available:

1
2
3
4
5
6
7
sendRequest(
    request: [method: 'GET', url: 'https://api.example.com/exchange-rates'],
    returnAs: 'Data Model Property',
    responseType: 'JSON',
    cacheName: 'exchangeRatesCache',
    cacheMode: 'eager'
)

Expected result: on the first call, sendRequest sends the request, receives a 2xx response, and caches it under a key derived from the method, URL, and query parameters. On subsequent calls with the same method, URL, and query parameters, sendRequest returns the cached response immediately, without sending a new request, until the cache entry expires per caches.conf or is manually invalidated.

Fallback Mode Example (HTTP 429)

Use fallback mode to keep calling the live service under normal conditions, but fall back to a cached response when the target API starts rate-limiting requests with HTTP 429:

1
2
3
4
5
6
7
sendRequest(
    request: [method: 'GET', url: 'https://api.example.com/exchange-rates'],
    returnAs: 'Data Model Property',
    responseType: 'JSON',
    cacheName: 'exchangeRatesCache',
    cacheMode: 'fallback'
)

Expected result: sendRequest sends the request every time. If the response is 2xx, it's returned and cached (replacing any previous entry for the same key). If the response is HTTP 429, sendRequest returns a previously cached response for the same key, if one exists, instead of the 429 response.

Default and Custom Cache Key Examples

Without cacheKey, two requests to the same URL and method with the same query parameters share a cache entry:

1
2
3
4
5
6
// This call uses the default cache key (method + URL + query parameters).
sendRequest(
    request: [method: 'GET', url: 'https://api.example.com/customers', parameters: [status: 'active']],
    cacheName: 'customersCache',
    cacheMode: 'eager'
)

Provide cacheKey to control the cache key explicitly — for example, to include a tenant or other response-varying context that is not part of the default key, or to share a cache entry only when differing headers do not affect the response:

1
2
3
4
5
6
7
8
def tenantId = 'tenant-a'

sendRequest(
    request: [method: 'GET', url: 'https://api.example.com/customers', parameters: [status: 'active']],
    cacheName: 'customersCache',
    cacheMode: 'eager',
    cacheKey: "active-customers-${tenantId}"
)

Expected result: each distinct cacheKey value gets its own cache entry, regardless of the request's method, URL, or query parameters.

Troubleshooting

Symptom Cause and Resolution
sendRequest always calls the web service, even repeatedly with the same request No cache entry exists yet for the resolved key (cache miss), the entry expired, or cacheName doesn't match a cache declared in caches.conf. Check for a "cache not found" warning in the logs and confirm the name in caches.conf.
Cached responses are returned longer/shorter than expected Expiry is controlled by the named cache's expireAfterWrite/expireAfterAccess settings in caches.conf, not by sendRequest. Adjust those settings on the cache, not the sendRequest call.
A stale response keeps being returned Invalidate or update the entry using the Cache Functions (for example cacheInvalidate/cacheInvalidatePattern), or shorten the cache's expireAfterWrite/expireAfterAccess in caches.conf. sendRequest has no per-call invalidation option.
A 4xx or 5xx response (other than 429 in fallback mode) is never cached and never served from cache Only 2xx responses are cached. Non-2xx responses always pass through as-is; a 4xx/5xx response is never written to the cache and, outside of the 429/fallback case, never replaced by a cached response.
Caching doesn't seem to work when returnAs is InputStream This is expected: caching is always skipped for InputStream responses, since the response body can't be replayed from the cache. Use String, byte[], or Data Model Property for returnAs if you need caching.
IllegalArgumentException is thrown when calling sendRequest cacheMode is required and must be eager or fallback whenever cacheName is provided. Supply a valid cacheMode, or omit cacheName if caching isn't needed.

Sending SOAP Requests with sendSoapRequest

sendSoapRequest sends a SOAP request and returns the response, replacing the deprecated HttpMethods.soap.

Getting Started

Invoke sendSoapRequest, providing at minimum a url and soapAction:

1
2
3
4
5
6
7
sendSoapRequest(
    url: 'https://soap.example.com/CustomerService',
    soapAction: 'GetCustomer',
    style: 'Document',
    soapProtocol: 'SOAP 1.1',
    messageBody: customerRequestModel
)

Parameters

Property Type Description
url String URL of the SOAP web service.
auth io.toro.martini.http.Auth Data Model Authentication info for the request.
soapAction String Name of the SOAP action.
style String SOAP message style, one of Document or RPC, indicating how the SOAP body is structured. This is a choice value, not a boolean flag.
soapProtocol String SOAP version to use for the envelope, one of SOAP 1.1 or SOAP 1.2.
messageHeader Data Model SOAP message header data.
messageBody Data Model SOAP message body.
trackable io.toro.martini.tracker.Trackable Data Model Tracking options for the call, recorded in Martini's Tracker.

Return Value

Returns a io.toro.martini.http.Response data model with the server's response data.

Required Properties

Requires url and soapAction properties for successful request sending.

Writing Ad Hoc HTTP Responses with writeResponse

writeResponse writes a custom HTTP response for an ad hoc REST service, replacing the deprecated HttpMethods.prepareResponse. In addition to the former response-writing parameters, writeResponse accepts a headers parameter for setting explicit response headers.

Parameters

Property Type Description
responseCode int HTTP status code to write to the response.
content Object Content to write as the response body.
format String Format used to serialize content (for example JSON or XML) when it is not already a raw string/byte payload.
headers array of io.toro.martini.http.Header Data Model Explicit response headers to set. Each entry is a header name/value reference model. Explicit headers here take precedence over any header Martini would otherwise derive from the content type.

Return Value and Exceptions

Unlike the deprecated prepareResponse, which swallowed and logged failures while returning a boolean success flag, writeResponse returns void and throws:

  • IOException — if the response could not be written to the underlying output stream.
  • IllegalArgumentException — if the supplied arguments are invalid, for example an unsupported format.

Callers must handle these exceptions explicitly; errors are no longer silently logged.

Using writeResponse with $requestHandled

For ad hoc REST services, invoke writeResponse and set the $requestHandled output property in the same invoke step/node, so Martini knows the response has already been written and should not generate one automatically:

1
2
3
4
5
6
7
try {
    HttpMethods.writeResponse(200, resultModel, 'JSON', headers)
    $requestHandled = true
} catch (IOException | IllegalArgumentException e) {
    LoggerMethods.error("Failed to write response", e)
    $requestHandled = false
}

Expected result: on success, the client receives the custom response you wrote and Martini does not attempt to generate its own; on failure, the exception is caught, logged, and $requestHandled reflects that the response was not written.

Reading Request/Response Headers with getRequestHeader/getResponseHeader

getRequestHeader and getResponseHeader are new functions for reading a single header value from the HttpServletRequest/HttpServletResponse objects made available by an HTTP Filter trigger — for example, the $__request and $__response parameters.

1
2
String getRequestHeader(HttpServletRequest request, String name)
String getResponseHeader(HttpServletResponse response, String name)
Function Parameters Return Value
getRequestHeader request (HttpServletRequest, required), name (String, required) The value of the named request header, or null if the header is not present.
getResponseHeader response (HttpServletResponse, required), name (String, required) The value of the named response header, or null if the header is not present.

request, response, and name must not be null. Neither function throws an exception when the requested header is simply absent — it returns null in that case.

1
2
3
4
String token = HttpMethods.getRequestHeader($__request, "Authorization")
if (token == null) {
    // Header not present; handle accordingly.
}

Checking Authentication with IdentityMethods.isAuthenticated

IdentityMethods.isAuthenticated replaces the deprecated HttpMethods.authenticated methods for checking whether an incoming request is authenticated. It accepts the same request and throwException parameters as the former method. For the full parameter reference, return value, and exception details, see Checking Authentication with isAuthenticated in the Identity Functions reference. That page also documents the new IdentityMethods.isAuthorized function for scope-based authorization checks outside REST API scope enforcement.

Migrating from Deprecated HttpMethods Functions

Martini Runtime v2.8.0 hid the following methods from the Functions view's content assist in favor of new, more discoverable replacements:

Deprecated method Replacement Notes
HttpMethods.authenticated(...) IdentityMethods.isAuthenticated(...) Same request and throwException parameters. throwException defaults to false.
HttpMethods.http(...) HttpMethods.sendRequest(...) http delegates to sendRequest for backward compatibility.
HttpMethods.sendRequest(...) (without cacheName/cacheMode/cacheKey) HttpMethods.sendRequest(...) (with cacheName/cacheMode/cacheKey) The prior sendRequest overload is hidden from the Functions view in favor of the version documented in Sending HTTP Requests with sendRequest, which adds the cacheName, cacheMode, and cacheKey parameters described in Reusing Cached Responses with sendRequest. The prior overload delegates to the new one, passing a blank cacheName, so existing calls behave exactly as before and are never cached.
HttpMethods.soap(...) HttpMethods.sendSoapRequest(...) soap delegates to sendSoapRequest for backward compatibility.
HttpMethods.prepareResponse(...) HttpMethods.writeResponse(...) Adds a headers parameter; returns void and throws IOException/IllegalArgumentException instead of returning a boolean success flag.

Deprecated does not mean unavailable

Deprecated methods and overloads are hidden from the Functions view's search results, but they are not removed. Workflows and services that already call HttpMethods.authenticated, HttpMethods.http, HttpMethods.soap, HttpMethods.prepareResponse, or the prior sendRequest overload without cache parameters keep working, because each deprecated method or overload delegates to its replacement. Migrate to the replacement names — and to the cache-aware sendRequest parameters, if useful — the next time you touch these workflows or services, since the deprecated methods no longer appear when searching for functions and may be removed in a future release.

Helpful Resources