---
title: HttpDefinition
description: "An `http` Effect's definition."
---

# `HttpDefinition`

Type, in `@jr2/orchestrator/src/http-effect.ts`. The signature of an export, or a type that it names, names this type. The [Authoring surface](../authoring-surface.md) page lists each export. This type is not an export of `@jr2/orchestrator`, so a workflow module does not import it by name.

```ts
type HttpDefinition<S extends z.ZodType | undefined = undefined> = {
  method: HttpMethod;
  url: string | Text | typeof open;
  headers?: Readonly<Record<string, string | Text>>;
  auth?: { readonly bearer: Secret } | { readonly basic: { user: Text; password: Text } } | Text;
  input?: S;
  request?: (input: S extends z.ZodType ? z.infer<S> : void) => HttpRequestParts;
  body?: FileBody<S>;
  timeout?: Duration;
  maxBody?: number;
  idempotent?: boolean;
};
```

An `http` Effect's definition.

**Fields**

- `method`: [`HttpMethod`](type-httpmethod.md)

  The HTTP method: `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` or `OPTIONS`. It refuses
  another: `http({ method: "<method>" }): the method is one of GET, HEAD, POST, PUT, PATCH,
  DELETE, OPTIONS`.
- `url`: `string | Text | typeof open`

  The url: `http://` or `https://`, then a literal host. No input, param or Effect secret can
  change where the call goes. An Effect secret can be only in the path:
  `` text`https://api.telegram.org/bot${secret("tg")}/sendMessage` ``.

  Or `open`: a packaged Machine that cannot know the host leaves the url Open, and the composer
  binds it one time with `customize(machine, { effects: { <slot>: { url } } })`.

  It refuses:
  - a scheme or host that is not literal: `` http({ url }): the url is an http:// or https:// url
    whose scheme and host are literal — a secret may sit only in its path, after a "/":
    text`https://api.example.com/bot${secret("tg")}/send` (ADR-0068) ``
  - an Effect secret after `?` or `#`: `` http({ url }): secret("<name>") sits in the url's query
    or fragment — a secret may sit only in its path; send it in `auth` or a header instead:
    headers: { "x-api-key": text`${secret("...")}` } (ADR-0068) ``
  - a host that is not a host: `http({ url }): "<scheme>://<host>" is not a host`
  - a user name or password in the url: ``http({ url }): the url carries userinfo — use `auth` ``
- `headers` (optional): `Readonly<Record<string, string | Text>>`

  Headers that are the same for each run. Each name is lowercase. A value is a string, or a
  `text` with an Effect secret.

  It refuses:
  - a name that is not lowercase, or that frames or routes the request (`host`,
    `content-length`, `transfer-encoding`, `connection`, `upgrade`, `te`, `trailer`,
    `keep-alive`, `proxy-*`): `http({ headers }): "<name>" is not a header an Effect sets — a
    lowercase name that does not frame or route the request (ADR-0068)`
  - an `authorization` header beside `auth`: ``http({ headers }): "authorization" is set by
    `auth` — write one of them``
- `auth` (optional): `{ readonly bearer: Secret; } | { readonly basic: { user: Text; password: Text; }; } | Text`

  The `Authorization` header: `bearer(secret("x"))`, `basic(user, password)`, or a `text` that
  is the whole value.
- `input` (optional): `S`

  The zod schema of the input of the Effect: what the `input` of the `invoke`, or `fromPick`,
  gives it. jr2 parses the input with it before the call. When it starts, input that does not
  agree with it makes the Effect fail (its `onError` route): `http "<slot>": its input does not
  match the definition's input schema — <path>: <message>`, one `<path>: <message>` for each
  problem, joined by `; `.
- `request` (optional): `(input: S extends z.ZodType ? z.infer<S> : void) => HttpRequestParts`

  A function that makes the part of the request that changes for each run, from the input:
  `path` segments, and a `json` or `text` body. It cannot change the host, a header or an
  Effect secret. Do not write it beside `body`.
- `body` (optional): `FileBody<S>`

  A Worktree file as the body: `file(path, { slot?, segments?, contentType? })`. The Effect then
  runs in the Sandbox Effector of its Workspace. Do not write `request` beside it: the `segments`
  of `file` are the path. It refuses another body: ``http({ body }): a body is file(path, {
  slot?, segments?, contentType? }) — json and text come from `request` ``.
- `timeout` (optional): [`Duration`](type-duration.md)

  How long jr2 waits for the answer: a number and a unit, such as `"30s"` or `"2m"`. Default
  `"30s"`. With no answer in that time, the output is `unknown`. It refuses a value that is not
  a positive duration: `http: timeout "<timeout>" is not a positive duration (like "30s",
  "2m")`.
- `maxBody` (optional): `number`

  The largest number of bytes of a text response body that the output keeps. Default 65536.
  When jr2 cuts the body, `truncated` is `true`. It refuses a value that is not a positive whole
  number: `http({ maxBody }): a positive number of bytes`.
- `idempotent` (optional): `boolean`

  `true` when it is safe to send the call two times: it has its own idempotency key, or it only
  reads. Default `false`. After an Orchestrator restart, jr2 cannot always tell if the call went
  out. Then it sends an idempotent call again, and gives any other call the output `unknown`.
