i'm new on fp-ts
, i'm trying to create a functional-like method that:
import { Request } from 'express';
import { either } from 'fp-ts';
import { pipe } from 'fp-ts/lib/function';
// * Parse the token
declare const parseRawToken: (rawToken: string | undefined) => either.Either<Error, string>;
// * Interface of the validate method
type MakeIsRequestAuthenticated = (
validateUserWithToken: (data: string) => Promise<either.Either<Error, void>>,
) => (request: Request) => Promise<either.Either<Error, void>>;
I want to chain these validations inside a pipe, so I tried to implement the validation by:
export const makeIsRequestAuthenticated: MakeIsRequestAuthenticated = validateUserWithToken => {
// * Validate the request
return async request => {
return pipe(
parseRawToken(request.header('Authorization')),
either.chain(validateUserWithToken)
);
};
};
but it gives my the following error:
Argument of type '(data: string) => Promise<Either<Error, void>>' is not assignable to parameter of type '(a: string) => Either<Error, void>'.
Type 'Promise<Either<Error, void>>' is not assignable to type 'Either<Error, void>'.ts(2345)
i had try replace the Promise
by a TaskEither
and some other solutions but none of them worked
I want to use the chain
or may other some method to be able to execute all these operations inside the pipe
Hope this can help:
import { Request } from 'express';
import { pipe } from 'fp-ts/lib/function';
import * as TE from "fp-ts/TaskEither";
import * as E from "fp-ts/Either";
import { assert } from 'console';
// * Parse the token (dummy implementation)
const parseRawToken = (rawToken: string | undefined) =>
rawToken ? E.right(rawToken) : E.left(new Error("Invalid token"));
// * Interface of the validate method (changed return type to TastEither<Error, Request>)
type MakeIsRequestAuthenticated = (
validateUserWithToken: (data: string) => TE.TaskEither<Error, void>,
) => (request: Request) => TE.TaskEither<Error, Request>;
//Actual implementation
export const makeIsRequestAuthenticated: MakeIsRequestAuthenticated =
validateUser => (request: Request) =>
pipe(
request.header("Authorization"), //returns string | undefined
parseRawToken, //returns Either<Error, string>
TE.fromEither, //To TaskEither
TE.chain(validateUser), //validate token
TE.map(() => request) //If no errors return request
)
//Mock request
const mockRequest = {
header: (name: string) => "fake token",
body: {
userName: "MsFake",
}
} as Request;
//Dummy implementations for tokenValidators: sucess and fail
const mockValidToken: (token: string) => TE.TaskEither<Error, void> =
(token: string) => TE.right(void 0);
const mockInValidToken: (token: string) => TE.TaskEither<Error, void> =
(token: string) => TE.left(new Error("Token not valid"));
//Test
const fail = makeIsRequestAuthenticated(mockInValidToken)(mockRequest);
const sucess = makeIsRequestAuthenticated(mockValidToken)(mockRequest);
sucess().then(d => assert(d._tag === "Right"));
fail().then(d => assert(d._tag === "Left"));
Now the method MakeIsRequestAuthenticated
returns a TaskEither<Error, Request>
and you can chain it with any method taking a Request
as a parameter. From now on you may deal with taskEither instead of promises, but it shouldn't be a problem.