I'm learning FP using fp-ts and as an exercise to learn how to use RTE
, I'm trying to (re)implement fetch-fp-ts. Here's what I've got so far:
import type { Request, Response } from "fetch-fp-ts";
import * as F from "fetch-fp-ts";
import * as E from "fp-ts/Either";
import * as R from "fp-ts/Reader";
import * as RTE from "fp-ts/ReaderTaskEither";
import * as TE from "fp-ts/TaskEither";
import { flow, pipe } from "fp-ts/function";
import nodeFetch from "node-fetch";
type E<A> = E.Either<Error, A>;
type TE<A> = TE.TaskEither<Error, A>;
type RTE<R, A> = RTE.ReaderTaskEither<R, Error, A>;
export interface FetchEnv {
fetch: (...args: Request) => TE<Response<number>>;
}
export const send: (r: Request) => RTE<FetchEnv, Response<number>> = r => {
return pipe(
R.ask<FetchEnv>(),
R.map(({ fetch }) => fetch(...r)),
);
};
Specifically here, I'd like to understand what's the best API for send
. For example how can I make the send
function point-free? What's the FP way of designing the send
function API?
Note: I understand that pushing too much for point-free is not recommended due to less readability, but here I'm trying to learn how the data should flow from one function to another. To make things concrete, here's an example of using send function:
// This is a function that gets an AWS SNS subscription message
// and confirms the subscription by calling the given URL!
export const subscriptionConfirmHttpHandler =
(env: FetchEnv) =>
(msg: Subscription): TE<undefined> => {
return pipe(
env,
Http.sendGET(msg.SubscribeURL), // `send` with GET verb!
TE.mapLeft(SubscriptionConfirmationFailedError.causedBy),
TE.map(_ => undefined), // discard response!
);
};
For example here there's two pieces of input; env
and msg
. What's the correct (FP) way of defining this function; should env
be first or msg
? Why? Is there a rule of thumb or something that can help with designing the API?
Thanks.