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 · 65e9465f
          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 decoding17. 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
    );
Simulated responseRequired outcome
200, integer versionDecoded version
503, otherwise valid bodyNamed status-phase failure
200, malformed JSONNamed body-phase failure
200, string instead of integerNamed body-phase failure

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 idempotency guarantee: whether repeating it can create a second change.
  2. Decide which failures allow another attempt.
  3. Measure the retry budget, 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 budget.

Common mistakes

Effect idiom and house rule

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

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-07 in f1a00f2. 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: feat(learn): teach cards 43 to 62 with plain lines, diagrams and snippets

  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. Effect basics. An Effect describes work, expected failures, and required services before a runtime executes it.

    HTTP responses: check status and decode accepted data.¶

  5. Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
  6. 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.

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

    HTTP success needs a status check and a decoder — edited: feat(learn): teach cards 43 to 62 with plain lines, diagrams and snippets

Unlinked mentions (1)
  • add-a-store → Check replay and interrupted execution when the new operation promises idempotency or atomicity.¶

Content updated .