Reputation: 927
I have this function and I wonder, how should one write it in FP style (with Ramda.js).
- registerUser(username, password) -> client_id, client_secret;
- getUserAccessToken(username, password, client_id, client_secret) -> access_token, refresh_token, refreshTokenExpiresAt;
- save to storage: client_id, client_secret, access_token, refresh_token, refreshTokenExpiresAt.
async function registerUser(username: string, password: string) {
try {
const { client_id, client_secret } = await authAPI.registerUser(username, password);
// get tokens
const {
access_token,
refresh_token,
refreshTokenExpiresAt,
} = await authAPI.getUserAccessToken(username, password, client_id, client_secret);
// save to async storage
store.update('user', {
client_id,
client_secret,
access_token,
refresh_token,
refreshTokenExpiresAt,
});
} catch (err) {
throw Error(err);
}
}
Upvotes: 0
Views: 141
Reputation: 21983
This has nothing to do with Ramda or FP. You've got one function doing three different things (auth, token request, and persistence) and that's your problem.
const registered = authAPI.registerUser(username, password)
.catch(err => showUserRegisterErr(err));
const token = registered.then(({client_id, client_secret}) => {
return Promise.all([
Promise.resolve({client_id, client_secret}),
authAPI.getUserAccessToken(
username,
password,
client_id,
client_secret
)
]);
});
const persisted = token.then((
{client_id, client_secret},
{access_token, refresh_token, refreshTokenExpiresAt}
) => {
return store.update('user', {
client_id,
client_secret,
access_token,
refresh_token,
refreshTokenExpiresAt,
});
});
persisted.catch(err => { throw err; });
Now these are all constant values, not functions, so lets fix that:
// No .catch, caller can catch errors if it wants. Also
// no more registerUser function, it was a thin layer over
// the auth API with error handling and we'll delegate to
// the caller for that.
const getToken = (username, password, registration) => {
return registration.then(({client_id, client_secret}) => {
return Promise.all([
username,
password,
client_id,
client_secret,
authAPI.getUserAccessToken(
username,
password,
client_id,
client_secret
)
]);
});
};
const persist = datastore => ([
client_id,
client_secret,
{
access_token,
refresh_token,
refreshTokenExpiresAt
}
]) => {
return store.update('user', {
client_id,
client_secret,
access_token,
refresh_token,
refreshTokenExpiresAt,
});
});
const persistToDB = persist(store);
const signUp = (username, password) => {
return getToken(username, password, authAPI.registerUser(username, password))
.then(persistToDB)
.catch(showUserRegistrationErr);
};
Now all the different pieces are independently testable. Since the registration is passed as a parameter to getToken
you can test it with a mock promise. Likewise with the persistence function. You can also mockout the authAPI.registerUser
function.
No state is mutated except in the persistence function, functions use only their parameters, etc. I also parameterized the datastore so that you can swap out persistence (or stub it for tests).
Upvotes: 2