1

I'm new to functional programming so a lot of things is still unclear for me. I'm trying to write my graphql server with fp-ts and I'm stuck with user authorisation. I'm expecting authorisation like: validate user data -> check is he existed -> encrypt his password -> create user. So this in types this looks like: Either<string, data> -> TaskEither<string, User> -> Either<string, data> -> TaskEither<string, User> And I don't have an idea for real who to chain this properly without type errors and with the possibility to ignore items in the pipe if Left(string) already has been gotten.

This is my database code:

import { pipe } from 'fp-ts/lib/function';
import { tryCatchK as encase } from 'fp-ts/lib/TaskEither';

export const findUser = (email: string) =>
  encase(
    () =>
      prisma.user.findOne({
        where: {
          email,
        },
      }),
    (rejection) => String(rejection),
  );

export const createUser = (data: UserCreation) =>
  encase(
    () => prisma.user.create({ data }),
    (rejection) => String(rejection),
  );

And this is my validation code:

import { sequenceT } from 'fp-ts/lib/Apply';
import { chain, fold } from 'fp-ts/lib/TaskEither';
import { getSemigroup, NonEmptyArray } from 'fp-ts/lib/NonEmptyArray';
import { getValidation, Either, mapLeft, map } from 'fp-ts/lib/Either';

const encrypt = (data: string) => hashSync(data);

const checkForDuplicate = (data: UserCreation) => findUser(data.email);

function lift<L, A>(
  check: (a: A) => Either<L, A>,
): (a: A) => Either<NonEmptyArray<L>, A> {
  return (a) =>
    pipe(
      check(a),
      mapLeft((b) => [b]),
    );
}

export const signUp = (data: UserCreation) =>
  pipe(
    sequenceT(getValidation(getSemigroup<any>()))(
      lift(validateSignUpData)(data),
      chain(checkForDuplicate),
    ),
    map(() => data),
  );

0 Answers0