Filtering with Custom Errors

Avatar of Hemanta SundarayHemanta Sundaray

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.

http.ts
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 it
Effect.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:

Terminal
Product: Essence Mascara Lash Princess - $9.99

The 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.

Sign in to save progress

Stay in the loop

Get notified when new chapters are added and when this course is complete.