Reason Tutorial Mashup using Context Part 2
Tags: reason, react, learning, tutorial
Published: 2019-11-12 20:34:29

---
title: Reason Tutorial Mashup using Context Part 2
published: true
description: Music Player in Reason With The useContext Hook + ReasonReact context explained In Action
tags: #reason #react #learning #tutorial 
series: Reason-Context-Mashup
---

In Part 1 we did the simple version which can be found here:


- [Reason Tutorial Mashup using Context Part 1](https://dev.to/idkjs/reason-tutorial-mashup-using-context-13l1)


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/a7ghsggl6a5sijt4qxtl.jpg)

Let kick it up a notch by trying it using [aws-amplify](https://aws-amplify.github.io/) authentication in this same app.

Plenty of stuff material around on setting up AWS. https://dev.to/dabit3 is good place to start. 

Once you have the `aws-cli` configured, run `amplify init` in the root of the project from [part 1](https://github.com/idkjs/brandt-plus-krutikova-simple).

It should look something like this:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ccv0783dx2xu3nqa2pmq.png)

Then run `amplify add auth` to get a `Cognito Identity Pool` and `Cognito User Pool` set up.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/twybu67ud7xhhh2o4y06.png)

Be sure to run `amplify push` to get all the backend set up in the cloud.

Since we didn't set up signing in we want to create a test user in our UserPool via the aws cognito interface on aws. That didn't sound clear, let me know if you don't get what I mean. In your terminal run `amplify console auth` which will open up that page.


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/61gjzb1mf1pch6knvbvs.png)

Select `User Pool` then enter. This will open up the AWS Cognito Users page in your User Pool. On the menu on the left, click `Users and Groups` then the blue outlined `Create User` button.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/yxzvlu2m6rjh02meqok4.png)

This is how I filled it out.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/yana9lxfwy1afudtsmyx.png)

The password I used was `Password12345@` so cognito wouldn't complain.

Even though it says that we will need to update the password, we are dealing with that here and it will let you use the temporary password for a while. Cognito will also send it to you in an email because we check that option.

## Setting Up Aws Auth In The App

### Bindings!

The first thing we want to do is add the `aws-amplify` package. We will use it to `configure` `aws-amplify` and run `auth` functions.

```ocaml
yarn add aws-amplify
touch Amplify.re // create a file for our Amplify binding.
```

Then create a file for our Amplify binding.

```ocaml
touch Amplify.re
```

In `Amplify.re` we want to add the following:

```ocaml
type t;
[@bs.module "aws-amplify"] external amplify: t = "default";
type config;
[@bs.module "./aws-exports.js"] external awsConfig: config = "default";

[@bs.send] external _configure: (t, config) => unit = "configure";
let configure = () => _configure(amplify, awsConfig);
```

What is going on here?

Ripped from [Patrick Kilgore](https://github.com/pckilgore)'s [BigInteger.re](https://github.com/pckilgore/bs-biginteger/blob/master/src/BigInteger.)
> What is `type t`?

> It is a ocaml convention for "the type of this module".  So if the module was named "Fish", `type t` would be the fish.  We could just as easily call it anything else, even `type fish`, but then we'd be referring to it as `Fish.fish` which seems silly, right? So we call it `type t` and refer to it as `Fish.t` and by convention know `t` means the module's type.

> A ReasonML module is a type packaged with its behavior.  In this way, it is similar to an Object-Oriented language's concept of `class`.

> So here, `type t` is the Amplify data structure, packaged with the methods we can to operate on that type.

> Because we don't really know (or, honestly, care) about _how_ the Amplify library implements the Amplify type, we just declare it here, which means it is an "abstract type", which I always think of as, "a type that must be used consistently by the functions that operate on it, but for which the particular implementation of the type and those functions are assumed to be correct".

Thanks, [Patrick](https://github.com/pckilgore) for taking the time to write those awesome comments.

So `t` is our `Amplify` javascript data structure bound to `aws-amplify`'s default export. 

The `type config` may or may not be overkill. I would love to hear back from you all on this. It works without it but its a pattern I picked up somewhere and this code works so moving on. We are using `bs.module` to import the `aws-exports.js` file that the `amplify-cli` generated in our `src` dir when we ran `amplify push`. It's got our configuration keys for accessing our auth service.


We are going to pass to that to Amplify's `configure` method/function which configures our app to use our services. We use `[@bs.send]` to call the function called `configure` on out `type t`. I aliased it as `_configure` so that I could call it using `configure`, no underscore later, and not hurt my eyes trying to see which `configure` function I was calling. In Reason, you can call them both `configure` and the second `configure` will just call the previous `configure`. 


Normally in JS it would look like this in your app's entry point:

```js
import Amplify, { Auth } from 'aws-amplify';
import awsconfig from './aws-exports';
Amplify.configure(awsconfig);
```

I went ahead and retrieve `aws-exports` and passed it to `configure` here. So in our app's entry point we can configure our app like so:

```ocaml
...other stuff
Amplify.configure(); //add this line
ReactDOMRe.renderToElementWithId(<Root />, "root");
```

Also in `Amplify.re` we want to add a binding to Amplify's `Auth` object. Let's add the following bindings and implementations functions:

```ocaml
/* assigning Amplify Auth object as type auth */
type auth;

[@bs.module "aws-amplify"] external auth: auth = "Auth";

[@bs.send] external _signOut: (auth, unit) => unit = "configure";


[@bs.send]
external _signIn:
  (auth, ~username: string, ~password: string, unit) => Js.Promise.t('a) =
  "signIn";

/* a function that calls Amplify's signOut to sign out our user. This works wether passing auth or amplify as our type t */

let signOut = () => _signOut(auth, ());

/* a function that takes a username and password then calls Amplify's signIn to sign in our user */

let signIn = (~username, ~password) =>
  _signIn(auth, ~username, ~password, ())
  |> Js.Promise.then_(res => Js.Promise.resolve(res));

```

By binding to the `Auth` object and assigning `type auth` we can use this same binding to call its functions using `[bs.send]`. We tell the compiler that the function is found on the `auth` binding by passing requiring an argument with type `auth` in our `bs.send` definitions like so: 

```ocaml
[@bs.send]
external _signIn:
  (auth, ~username: string, ~password: string, unit) => Js.Promise.t('a) =
  "signIn";

``` 

The implementation is written so that when we call `signIn` it only requires the `username` and `password` which we then pass to the the underscore `signIn` which already has the `auth` binding called in it.

```ocaml

let signIn = (~username, ~password) =>
  _signIn(auth, ~username, ~password, ())
  |> Js.Promise.then_(res => Js.Promise.resolve(res));

```

I am pretty sure, this is what they call [`currying`](https://reasonml.github.io/docs/en/syntax-cheatsheet#currying). The docs aren't very helpful so let me take a stab at explaining it to us. The `_signin` already has the `auth` property and is just waiting on the last two variables that it needs to be able to make the call. These remaining variables are the `username` and `password` values we pass into `signIn()`. This makes it so we don't have to pass in the `auth` property at the call sites every time we want to use the module. Anyone with a better explanation, please teach me! 


### Using Our Binding

Now that we have the binding, let use them in the `Header.re` module.

We are going to add to functions that will handle `signIn` and `signOut`.

```ocaml
// ...other code
let handleSignin = () =>
    Js.Promise.(
      Amplify.signIn(~username, ~password)
      |> then_(res => {
           //  Js.log2("res", res);
           // this is bad, i think, because we aren't handling errors. We know, for purposes of the example, that the username is at the `username` key so let's go with it.
           let username = res##username;

           Js.log("sign in success!");
           dispatch(UserLoggedIn(username));
           resolve();
         })
      |> catch(err => {
           Js.log(err);
           let errMsg = "error signing in.." ++ Js.String.make(err);
           Js.log(errMsg);
           resolve();
         })
      |> ignore
    );
  let handleSignOut = () => {
    Amplify.signOut();
    dispatch(UserLoggedOut);
    Js.log("signing out!");
    /* test if user is logged out because you can still log the user after logging out. Running currentAuthenticated user shows that we are logged out so why is `user` logging out below?*/
    Amplify.currentAuthenticatedUser
    |> Js.Promise.then_(data => {
         Js.log2("data", data);
         Js.Promise.resolve(data);
       })
    |> Js.Promise.catch(error => Js.log2("error", error)->Js.Promise.resolve)
    |> Js.Promise.resolve
    |> ignore;
    /* user still logs after logging out. Why? */
    Js.log2("signing out user!",user);
  };

// ...other code

```

The `handleSignIn` function is going to read the `username` and `password` off of our state and call `Amplify.signIn` with it. If we get a positive answer, then we read the `username` key off of the response object,`res##username` and set it in our user context by calling `dispatch(UserLoggedIn(username))`. The `##` is how you read the value at a key on a javascript object. See Accessors in the bucklescript [docs](https://bucklescript.github.io/docs/en/object-2#read).


The `handleSignOut` is pretty simple since it doesn't return anything. I added a call to `currentAuthenticatedUser` because you can still log the username after signing out. In fact, the `currentAuthenticatedUser` response shows that we are signed out. If anyone wants to tell me why the username is still logging, I would love to understand it. I though it would error or return `Anonymous`. Idea? Ideas? Thank's in advance.

Now let change:

```ocaml

| Anonymous =>
    <form
      className="user-form"
      onSubmit={e => {
        ReactEvent.Form.preventDefault(e);
        dispatch(UserLoggedIn(userName));
      }}>

```

To: 

```ocaml

  | Anonymous =>
    <form
      className="user-form"
      onSubmit={e => {
        ReactEvent.Form.preventDefault(e);
        handleSignin();
      }}>
```

And further down, change:

```ocaml
| LoggedIn(userName) =>
    <div className="user-form">
      <span className="logged-in">
        {s("Logged in as: ")}
        <b> {s(userName)} </b>
      </span>
      <div className="control">
        <button
          className="button is-link"
          onClick={_ => dispatch(UserLoggedOut)}>
          {s("Log Out")}
        </button>
        </div>
    </div>

```

to:

```ocaml
| LoggedIn(userName) =>
    <div className="user-form">
      <span className="logged-in">
        {s("Logged in as: ")}
        <b> {s(userName)} </b>
      </span>
      <div className="control">
       <button className="button is-link" onClick={_ => handleSignOut()}>
      </div>
    </div>
```

That's it. Now you are using Aws Cognito to for overkill authentication in Ms. Brandt's music app.

Reach with questions or lessons, please. Thank you!

Check out this version on the [with-aws branch](https://github.com/idkjs/brandt-plus-krutikova-simple/tree/with-aws)