Both filterStatusOk and filterStatus only look at the status code, and they always produce an HttpClientError. But sometimes you want to filter on other properties of the response — a specific header value, a content type, or a combination of conditions — and produce your own custom error.
HttpClient.filterOrFail() lets you do exactly that. It takes a predicate over the full response object and an error constructor. If the predicate returns false, the error you provide is placed in the error channel.
import { FetchHttpClient, HttpClient, HttpClientRequest,} from "effect/unstable/http";import { Data, Effect } from "effect";
class UnexpectedContentType extends Data.TaggedError("UnexpectedContentType")<{ readonly expected: string; readonly actual: string | undefined;}> {}
function fetchJsonProduct(productId: number) { return Effect.gen(function* () { const client = (yield* HttpClient.HttpClient).pipe( HttpClient.filterStatusOk, // Ensure the response is JSON before we try to parse it HttpClient.filterOrFail( (response) => response.headers["content-type"]?.includes("application/json") ?? false, (response) => new UnexpectedContentType({ expected: "application/json", actual: response.headers["content-type"], }), ), );
const request = HttpClientRequest.get( `https://dummyjson.com/products/${productId}`, );
const response = yield* client.execute(request); const product = yield* response.json;
return product; }).pipe(Effect.provide(FetchHttpClient.layer));}
// Test itEffect.runPromise(fetchJsonProduct(1)).then( (product) => console.log("Product:", product.title, `- $${product.price}`), (error) => { if (error._tag === "UnexpectedContentType") { console.error(`Expected ${error.expected}, got ${error.actual}`); } else { console.error("Error:", error.message); } },);Output:
Product: Essence Mascara Lash Princess - $9.99The first argument to filterOrFail is a predicate that receives the HttpClientResponse. If it returns true, the response passes through unchanged. If it returns false, the second argument — the error constructor — is called with the response, and the resulting error is placed in the error channel.
Notice that the error type (UnexpectedContentType) is fully custom. It’s not an HttpClientError. This lets you integrate response filtering into your application’s own error hierarchy.
filterOrFail is useful for hard validation: if the response doesn’t meet your criteria, there’s no recovery at the client level. The error propagates to the caller.