HTTP Quickstart
Build your first real integration: an HTTP endpoint that transforms requests.
This page builds a small orders API that routes on the request method and
answers with JSON. It is a trimmed-down samples/http-orders.yaml.
The flow
Save this as orders.yaml:
service:
name: orders-api
connectors:
- name: api
type: http
settings:
port: 8080
basePath: /api/v1
flows:
- name: orders
source:
connector: api
type: http
settings:
path: /orders/{id}
process:
- type: switch
name: route-by-method
cases:
- when: 'vars.method == "GET"'
process:
- type: set-payload
name: lookup-order
settings:
value: '{"orderId": vars.id, "status": "found"}'
- when: 'vars.method == "POST"'
process:
- type: set-payload
name: accept-order
settings:
value: '{"orderId": vars.id, "item": body.item, "status": "accepted"}'
default:
process:
- type: set-payload
name: method-not-supported
settings:
value: '{"error": "method " + vars.method + " not supported"}'The http connector owns one HTTP server (bind address, port, base path,
timeouts), here on port 8080 under /api/v1. The source registers a route on
it, and path: /orders/{id} makes {id} available as vars.id. The switch
block runs the process chain of the first case whose when is true, or
default when none matches; the set-payload blocks build the response body,
which is written back to the caller as JSON with status 200.
Run it and call it
bin/octo run --config orders.yamlIn another terminal:
curl -s localhost:8080/api/v1/orders/42{"orderId":"42","status":"found"}curl -s -X POST localhost:8080/api/v1/orders/42 -d '{"item":"widget"}'{"item":"widget","orderId":"42","status":"accepted"}curl -s -X DELETE localhost:8080/api/v1/orders/42{"error":"method DELETE not supported"}The message model in one minute
Every request becomes a message with two parts. body is the payload: it
starts as the parsed request body (the POST's {"item":"widget"}), blocks like
set-payload replace it, and the final body is the HTTP response. vars holds
named variables alongside the body: the HTTP source sets vars.method,
vars.id from the {id} path segment, and vars.query (a map of query
parameters), and blocks like set-variable add your own. The switch decides
on vars.method while the body stays whatever the caller sent. See
State and Data for the full model.
Run with --watch while you iterate: edit a when expression or a response
body, save, and the endpoint reloads without a restart.
Put it under test
Three curl calls proved the three branches once. A suite proves them on every
edit, and it does not need the server: under test no source runs, so the case
builds the message the HTTP source would have built. Save this beside the flow
as orders_test.yaml:
flow: orders
cases:
- name: a GET returns the order
input:
vars: { method: GET, id: "42" }
expect:
body: { orderId: "42", status: found }
- name: a POST accepts the item in the body
input:
vars: { method: POST, id: "42" }
data: { item: widget }
expect:
body: { orderId: "42", item: widget, status: accepted }
- name: any other method is refused
input:
vars: { method: DELETE, id: "42" }
expect:
body: { error: "method DELETE not supported" }input.vars is doing the work the source normally does: vars.method is what
the switch routes on, and vars.id is the {id} path segment. input.data
is the request body, which only the POST case needs.
export OCTO_PATH=$PWD/bin/octo
bin/dolphin test orders.yamlok orders_test.yaml (orders) 141ms
3 passed, 0 failed, 0 errored, 0 skipped (141ms)One case per branch, including the branch you hope never runs. See Unit-Testing a Flow for what else a case can assert.
Next steps
The full samples/http-orders.yaml adds environment variables for the host and
port, request logging, captured headers, correlation IDs, and flow composition
with flow-ref. The REST API guide covers production
endpoints: validation, status codes, and error handling.