简体   繁体   中英

How to pipe and chain an operation that uses multiple `Eithers` and `Promises` from `fp-ts`

i'm new on fp-ts , i'm trying to create a functional-like method that:

  1. Parse a bearer token
  2. Check if the user is valid using the parsed token
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.

  • I've modified a litle the interface of the validate method to return the request, allowing another handler to take it and do whatever after validation
  • I've modified the interface of validateUserWithToken to return TaskEither<Error, void> instead of promise.
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.map(validateUser), //validate token, returns TE.TaskEither<Error, TE.TaskEither<Error, void>>
            TE.flatten, //To unwrap nested TaskEither<Error, void> 
            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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM