...

/

Dealing with the Asynchronous Calls

Dealing with the Asynchronous Calls

Learn to deal with asynchronous calls. Additionally, deploy and test our application.

Let’s take another look at the entrypoint of our pets folder. Here’s some relevant code:

Press + to interact
export const getPet = async (event: APIGatewayProxyEventV2): Promise<Response> =>
pipe(
preparePetGet(event),
TE.fromEither,
TE.chain(retrieveFromDatabase),
TE.map(JSON.stringify),
TE.bimap(handleError, okResponse),
TE.getOrElse(T.of)
)();
export const postPet = async (event: APIGatewayProxyEventV2): Promise<Response> =>
pipe(
preparePetPost(event),
TE.fromEither,
TE.chain(putInDatabase),
TE.bimap(handleError, createdResponse),
TE.getOrElse(T.of)
)();

We discussed the prepare step, where we validate the event we received and transform it into a domain object.

TaskEither for asynchronous calls

We also see some functions related to the database (retrieveFromDatabase and putInDatabase). As these are asynchronous calls, once again we’ll use a very useful monad transformer called TaskEither. As we saw in earlier chapters, we can use fromEither to lift our existing monad into a TaskEither, making our subsequent work with our new favorite monad easier.

Going further downstream to our database files, we see it’s composition and piping all the way down, because all exported functions are composed of smaller functions:

Press + to interact
const buildGet = (request: RetrievePetRequest) => ({
TableName: process.env.DATABASE_NAME,
Key: {
ppId: `${PETS_ID_PREFIX}#${request.clientId}`,
psId: request.id,
},
});
const buildPost = (request: AddPetRequest) => ({
TableName: process.env.DATABASE_NAME,
Item: {
ppId: `${PETS_ID_PREFIX}#${request.clientId}`,
psId: request.id,
id: request.id,
clientId: request.clientId,
name: request.name,
age: request.age,
cuteness: request.cuteness,
type: request.type
}
});
export const retrieveFromDatabase = (request: RetrievePetRequest) =>
pipe(
buildGet(request),
(params) => TE.tryCatch(() => get(params), serverError),
TE.chain(checkEmptyTE),
TE.map(getItem)
);
export const putInDatabase = (request: AddPetRequest) =>
pipe(
buildPost(request),
(params) => TE.tryCatch(() => post(params), serverError),
);

Use of parameters

The first step is building the right parameters for our call, for which we have some simple, pure functions. In the next step, we pass these params to the actual DynamoDB call inside the TaskEither ...