HTTP success needs a status check and a decoder

Schema defines accepted values and checks data at runtime. An adapter implements an application interface for a provider.

A fulfilled HTTP request is not proof of application success. Check the status and decode the body before passing provider data into the application. Use the effect/http modules.

Check the protocol response

The deployment checker decodes tool discovery through ToolsResponse. It also requires status 200 and the expected tool names.

packages/deploy/src/checks.ts · b4d6b8f4
          const document =
            yield* HttpClientResponse.schemaBodyJson(ToolsResponse)(response);

          return (
            response.status === 200 &&
            ["search", "read", "execute"].every((name) =>
              document.result.tools.some((tool) => tool.name === name)
            )
          );
        })

Use the in-memory fixture below when learning.

Reject an unacceptable response before trusting its data

HttpClient.filterStatusOk accepts 2xx status codes. An adapter can require a narrower status when its protocol needs one. The fixture applies the filter before decoding a version response.

packages/deploy/test/fixtures/validated-http-response.ts · 4019cffb
    const client = (yield* HttpClient.HttpClient).pipe(
      HttpClient.filterStatusOk
    );

    const response = yield* client
      .get("https://provider.example.test/version")
      .pipe(
        Effect.mapError(
          (cause) => new ResponseFixtureError({ cause, phase: "status" })
        )
      );

    return yield* HttpClientResponse.schemaBodyJson(Reply)(response).pipe(
      Effect.mapError(
        (cause) => new ResponseFixtureError({ cause, phase: "body" })
      )
    );
  }

schemaBodyJson handles JSON parsing and schema decoding25. ResponseFixtureError retains the cause and names the failed phase.

The fixture groups request and status failures into its status phase. It groups parsing and schema failures into its body phase. A production adapter should choose failure names that match its job and repair path.

Supply the transport in tests

The test supplies a client that creates responses in memory. It does not start an HTTP server or call a provider.

packages/deploy/test/http-response.test.ts · 4019cffb
      Effect.sync(() =>
        HttpClientResponse.fromWeb(
          request,
          new Response(scenario.body, {
            headers: { "content-type": "application/json" },
            status: scenario.status,
          })
        )
      )
    );

    const result = yield* readValidatedResponse().pipe(
      Effect.provideService(HttpClient.HttpClient, client),
      Effect.result
    );

These tests of the HTTP client interface establish the fixture’s status and decoding policy. Check live endpoint health separately.

Decide whether replay is safe before adding retries

A transient failure may be temporary. retryTransient can retry transient responses and errors. Its classification does not prove that repeating an operation is safe. A write can complete remotely even when its response is lost.

Before retrying a write:

  1. Identify the operation’s replay or idempotency14 guarantee: whether repeating it can create a second change.
  2. Decide which failures allow another attempt.
  3. Measure the retry budget10, the allowed attempts or time, and select the schedule.
  4. Preserve the final named failure when the budget ends.

Do not copy example delays or retry counts into production as measured limits. The fixture establishes no production retry budget10.

Common mistakes

Effect idiom and house rule

Read schemas25 and failures39 before defining the adapter’s accepted data. Then read tracing7 to observe the operation without exposing private values. Return to the Effect reading order29.

Sources

  1. Effect contributors. 2026. HttpClient. Effect 4.0.0.. Effect-TS. filterStatusOk rejects non-2xx responses; retryTransient classifies retryable errors and responses but does not establish application replay safety. Accessed 2026-10-06.
  2. Effect contributors. 2026. HttpClientResponse.. Effect-TS. schemaBodyJson parses a JSON response and decodes it through the supplied Schema. Accessed 2026-10-06.
  3. Effect contributors. 2026. Getting started with HttpClient.. Effect-TS. Supplied clients, request middleware, response decoding, named adapter errors, and request construction. Accessed 2026-10-06.
  4. rat-stack contributors. 2026. Deployment behavior checks.. rat-stack. A protocol check validates response status and schema-decoded tool discovery before reporting behavior-confirmed. Accessed 2026-10-06.
  5. rat-stack contributors. 2026. HTTP response fixture.. rat-stack. A supplied in-memory client exercises valid data, non-2xx status, malformed JSON, and a wrong decoded field type. Accessed 2026-10-06.
  6. Langton, Kit. 2026. HTTP Clients. Effect Solutions.. Kit Langton. The draft frames middleware and response decoding. This guide uses exact stable-version source and independent fixtures. Accessed 2026-10-06.

Last changed 2026-10-24 in abefe39. Source on GitHub. Change log.

Linked from

  1. Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.

    HTTP success needs a status check and a decoder — Supply the client, check the response status, decode accepted data, and name failures at the adapter boundary.

  2. Change log. What changed in the files served here, newest first.

    HTTP success needs a status check and a decoder — edited: fix(site): replace published Markdown tables with lists and fence reader output

  3. Concurrent work needs an owner and a bound. Limit active work, retain result order, and stop child work when its owning lifetime ends.

    Next, validate HTTP responses before treating concurrent provider work as successful.¶

  4. Durability. Seven durable Effect patterns, each with its seam, its fence, and the incident that taught it.

    Primitive: waitUntil at the edge, with a backstop that replays the same idempotency key.¶

  5. Effect basics. An Effect describes work, expected failures, and required services before a runtime executes it.

    HTTP responses: check status and decode accepted data.¶

  6. Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
  7. onboard-a-list. Analyze or migrate an email list. Measure sanitation rules, preserve stops, choose a cohort, and verify an authorized import or sending cutover.

    Use tenant-scoped idempotency keys and durable resume checkpoints.¶

  8. Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.

    HTTP success needs a status check and a decoder — Supply the client, check the response status, decode accepted data, and name failures at the adapter boundary.

  9. Source change history (log.md). The generated change log as Markdown.

    HTTP success needs a status check and a decoder — edited: fix(site): replace published Markdown tables with lists and fence reader output

Content updated .