Most real-world file upload APIs expect the file as part of a multipart form data body, not as the raw request body. This is because the server often needs additional fields alongside the file: a title, a description, access permissions, and so on.
You can combine files and text fields using FormData:
import { FetchHttpClient, HttpClient, HttpClientRequest,} from "effect/unstable/http";import { Effect } from "effect";
function uploadAvatar(username: string) { return Effect.gen(function* () { const client = yield* HttpClient.HttpClient;
// Create a file (in a browser, this would come from <input type="file">) const avatarFile = new File(["<fake image bytes>"], "avatar.png", { type: "image/png", });
const formData = new FormData(); formData.append("username", username); formData.append("avatar", avatarFile);
const request = HttpClientRequest.post("https://httpbin.org/post").pipe( HttpClientRequest.bodyFormData(formData), );
const response = yield* client.execute(request); const data = yield* response.json;
return data; }).pipe(Effect.provide(FetchHttpClient.layer));}
// Test itEffect.runPromise(uploadAvatar("emilys")).then((data) => { console.log("Form fields:", data.form); console.log("Files:", Object.keys(data.files));});Output:
Form fields: { username: 'emilys' }Files: [ 'avatar' ]The server receives both the text field (username) and the file (avatar) in a single request. The multipart encoding keeps them separate, each with their own content type and metadata.