Publish / http · All operations

Return an HTTP response to the caller

A variant of Send to a web endpoint

Build the status, headers and body of the response a pipeline served as a web service returns to the client that called it.

Status

In arcform

Runs as a SQL step

arcform carries it as a sql: step today.

The DuckDB step

Build the status, headers and body of a response for each request

It reads the orders table the proofs share. Create it first:

SQL
CREATE TABLE orders AS SELECT * FROM (VALUES
  (1,  'Alice Ng',      'north', DATE '2026-01-03', 120.00, 'widget', 'a|b',   '{"channel":"web","items":[1,2]}'),
  (2,  'alice ng',      'north', DATE '2026-01-05',  80.50, 'gadget', 'b',     '{"channel":"shop","items":[3]}'),
  (3,  'Bob  Okafor',   'south', DATE '2026-01-05', 300.00, 'widget', 'a|c',   '{"channel":"web","items":[4,5,6]}'),
  (4,  'Carla Díaz',    'east',  DATE '2026-01-09',  NULL,  'gizmo',  NULL,    '{"channel":"web","items":[]}'),
  (5,  'Bob Okafor',    'south', DATE '2026-01-12',  45.25, 'gadget', 'c',     '{"channel":"phone","items":[7]}'),
  (6,  'Dev Patel',     'west',  DATE '2026-01-12', 510.00, 'widget', 'a',     '{"channel":"web","items":[8,9]}'),
  (7,  'Carla Diaz',    'east',  DATE '2026-01-20',  99.99, 'gizmo',  'b|c',   '{"channel":"shop","items":[10]}'),
  (8,  'Dev Patel',     'west',  DATE '2026-02-02', 510.00, 'widget', 'a',     '{"channel":"web","items":[8,9]}'),
  (9,  'Eve Larsen',    NULL,    DATE '2026-02-03',  15.00, 'gadget', NULL,    '{"channel":"web","items":[11]}'),
  (10, 'Alice Ng',      'north', DATE '2026-02-10', 220.00, 'gizmo',  'a|b|c', '{"channel":"phone","items":[12,13]}')
) t(order_id, customer, region, order_date, amount, product, tags, meta);

Then run the statement:

SQL
CREATE TEMP TABLE requests AS SELECT * FROM (VALUES (1, 6), (2, 4), (3, 99)) t(request_id, order_id);
-- a found order is a 200 with its JSON; one that is not found is a 404 with an error body
CREATE TEMP TABLE responses AS
SELECT r.request_id,
       CASE WHEN o.order_id IS NULL THEN 404 ELSE 200 END AS status,
       CASE WHEN o.order_id IS NULL THEN to_json({'error': 'order ' || r.order_id || ' not found'})::VARCHAR
            ELSE to_json({'order_id': o.order_id, 'customer': o.customer, 'amount': o.amount})::VARCHAR END AS body
FROM requests r LEFT JOIN orders o USING (order_id);
CREATE TEMP TABLE result AS
SELECT request_id, status,
       MAP {'Content-Type': 'application/json; charset=utf-8', 'Content-Length': octet_length(encode(body))::VARCHAR} AS headers, body,
       'HTTP/1.1 ' || status || ' ' || CASE status WHEN 200 THEN 'OK' WHEN 404 THEN 'Not Found' END || chr(13) || chr(10)
         || 'Content-Type: application/json; charset=utf-8' || chr(13) || chr(10)
         || 'Content-Length: ' || octet_length(encode(body)) || chr(13) || chr(10) || chr(13) || chr(10) || body AS wire
FROM responses;
SELECT request_id, status, headers, body FROM result ORDER BY request_id;
SELECT CASE WHEN ((SELECT list(status ORDER BY request_id) FROM result) = [200, 200, 404] AND (SELECT headers['Content-Length'] FROM result WHERE request_id = 2) = '53' AND (SELECT wire FROM result WHERE request_id = 3) = 'HTTP/1.1 404 Not Found' || chr(13) || chr(10) || 'Content-Type: application/json; charset=utf-8' || chr(13) || chr(10) || 'Content-Length: 30' || chr(13) || chr(10) || chr(13) || chr(10) || '{"error":"order 99 not found"}' AND (SELECT body FROM result WHERE request_id = 2) = '{"order_id":4,"customer":"Carla Díaz","amount":null}') THEN 'as expected' ELSE error('the requests did not get a 200, a 200 and a 404 with a Content-Length counted in bytes and the response laid out as HTTP') END AS verdict;
  • It needs nothing installed beyond DuckDB itself.
  • The statement checks its own result and raises an error when it is wrong: “the requests did not get a 200, a 200 and a 404 with a Content-Length counted in bytes and the response laid out as HTTP”.
  • It passed on DuckDB v2.0.0 (Cyanoptera) d54cbbe3df.

What other tools call it

Meridian's classification; an independent blind rating agreed on 95.7% of 324 rows (variant, version 3).

Apache NiFi (1)
  • HandleHttpResponseread 2026-09-27

    Send the HTTP response for a FlowFile that HandleHttpRequest created

EasyMorph (1)
KNIME Analytics Platform (1)
Talend (3)
  • tAPIOperationResponseread 2026-09-27

    Return a response with the status code and payload model the API contract defines

  • tESBProviderResponseread 2026-09-27

    Return the result of a Job cycle as the response message of the web service the Job provides

  • tRESTResponseread 2026-09-27

    Return a chosen HTTP status code to the client as the response to its request

Background

A Hypertext Transfer Protocol (HTTP) response is the message a server sends back in reply to a request, letting the client know the outcome of the request.[1][2] In Apache NiFi, the HandleHttpResponse processor is designed to be used with HandleHttpRequest, so that a flow can act as a web service.[3] KNIME's Container Output (Raw HTTP) node produces a raw HTTP response, with headers, body and status code configurable via input tables and dialog options.[4]

When to use it

The status line of an HTTP response holds the protocol version, a numeric status code saying whether the request succeeded or failed, and an optional reason phrase.[2] HTTP status codes are grouped in five classes: informational (100 to 199), successful (200 to 299), redirection (300 to 399), client error (400 to 499) and server error (500 to 599).[5] The status 404 Not Found means the server cannot find the requested resource.[5] Pick the status from each request's outcome, so that a caller can tell a missing record from a found one without reading the body. (Meridian's view)

NiFi's HandleHttpResponse routes to failure when it cannot respond, for instance if the connection times out or NiFi is restarted before it responds.[3] A KNIME workflow can hold only one Container Output (Raw HTTP) node, and the node is compatible only with the Container Input (Raw HTTP) node.[4] Keep the steps between receiving a request and answering it short. (Meridian's view)

If no content-type header is given, KNIME's Container Output (Raw HTTP) returns application/octet-stream.[4] Set the response's content type explicitly rather than leaving it to a tool's default. (Meridian's view) In EasyMorph, a complex response body should be built in a column, with the actions and functions EasyMorph provides, before the Construct HTTP response action.[6]

The method

In HTTP/1.x, each response header is a case-insensitive string followed by a colon and a value whose format depends on the header.[2]

KNIME's Container Output (Raw HTTP) sends the content of the first cell of a string or binary column as the response body.[4] KNIME's Container Output (Raw HTTP) can send arbitrary data back to the client, such as an Excel spreadsheet, or a web page generated on request.[4]

EasyMorph's Construct HTTP response action builds the fields required for an HTTP response, and needs a connection to an EasyMorph Hub space.[6] EasyMorph's Construct HTTP response action offers four response types: Success, File download, Redirect and Error.[6] For the Error response type, EasyMorph offers the codes 400 Bad Request, 401 Unauthorized, 403 Forbidden and 500 Internal Server Error.[6] For the Redirect response type, EasyMorph offers 302 Found, 303 See Other, 307 Temporary Redirect and 308 Permanent Redirect.[6]

In Apache NiFi, HandleHttpResponse takes the response's status code from its HTTP Status Code property, and sets response headers from its dynamic properties.[3]