Skip to content

Commit

Permalink
Amplify update (#207)
Browse files Browse the repository at this point in the history
* Edit chapters

* Initial draft for Amplify update

* Editing chapters

* Moving sigv4client to separate chapter

* - Fixing code links
- Fixing styles for the about page

* Add --delete flag to s3 upload

* Update notice
  • Loading branch information
jayair authored Mar 15, 2018
1 parent 40a4747 commit 82ee17f
Show file tree
Hide file tree
Showing 52 changed files with 495 additions and 584 deletions.
1 change: 0 additions & 1 deletion _chapters/add-app-favicons.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ title: Add App Favicons
date: 2017-01-07 00:00:00
description: To generate app icons and favicons for our React.js app we will use the Realfavicongenerator.net service. This will replace the default favicon that Create React App comes with.
context: frontend
code: frontend
comments_id: 30
---

Expand Down
1 change: 0 additions & 1 deletion _chapters/add-the-create-note-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ title: Add the Create Note Page
date: 2017-01-22 00:00:00
description: We would like users to be able to create a note in our React.js app and upload a file as an attachment. To do so we are first going to create a form using the FormGroup and FormControl React-Bootstrap components.
context: frontend
code: frontend
comments_id: 47
---

Expand Down
46 changes: 31 additions & 15 deletions _chapters/add-the-session-to-the-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ date: 2017-01-15 00:00:00
redirect_from: /chapters/add-the-user-token-to-the-state.html
description: We need to add the user session to the state of our App component in our React.js app. By lifting the state up we can pass the session to all the child containers.
context: frontend
code: frontend
comments_id: 39
---

Expand Down Expand Up @@ -60,7 +59,17 @@ const childProps = {

Currently, our `Routes` component does not do anything with the passed in `childProps`. We need it to apply these props to the child component it is going to render. In this case we need it to apply them to our `Login` component.

<img class="code-marker" src="/assets/s.png" />To do this, create a new component in `src/components/AppliedRoute.js` and add the following.
To do this we are going to create a new component.

<img class="code-marker" src="/assets/s.png" />Create a `src/components/` directory by running this command in your working directory.

``` bash
$ mkdir src/components/
```

Here we'll be storing all our React components that are not dealing directly with our API or responding to routes.

<img class="code-marker" src="/assets/s.png" />Create a new component in `src/components/AppliedRoute.js` and add the following.

``` coffee
import React from "react";
Expand Down Expand Up @@ -113,33 +122,40 @@ this.props.userHasAuthenticated(true);
We can now use this to display a Logout button once the user logs in. Find the following in our `src/App.js`.

``` coffee
<RouteNavItem href="/signup">Signup</RouteNavItem>
<RouteNavItem href="/login">Login</RouteNavItem>
<LinkContainer to="/signup">
<NavItem>Signup</NavItem>
</LinkContainer>
<LinkContainer to="/login">
<NavItem>Login</NavItem>
</LinkContainer>
```

<img class="code-marker" src="/assets/s.png" />And replace it with this:

``` coffee
{this.state.isAuthenticated
? <NavItem onClick={this.handleLogout}>Logout</NavItem>
: [
<RouteNavItem key={1} href="/signup">
Signup
</RouteNavItem>,
<RouteNavItem key={2} href="/login">
Login
</RouteNavItem>
]}
: <Fragment>
<LinkContainer to="/signup">
<NavItem>Signup</NavItem>
</LinkContainer>
<LinkContainer to="/login">
<NavItem>Login</NavItem>
</LinkContainer>
</Fragment>
}
```

Also, import the `NavItem` in the header.
Also, import the `Fragment` in the header.

<img class="code-marker" src="/assets/s.png" />Replace the `react-bootstrap` import in the header of `src/App.js` with the following.
<img class="code-marker" src="/assets/s.png" />Replace the `import React` line in the header of `src/App.js` with the following.

``` coffee
import { Nav, NavItem, Navbar } from "react-bootstrap";
import React, { Component, Fragment } from "react";
```

The `Fragment` component can be thought of as a placeholder component. We need this because in the case the user is not logged in, we want to render two links. To do this we would need to wrap it inside a single component, like a `div`. But by using the `Fragment` component it tells React that the two links are inside this component but we don't want to render any extra HTML.

<img class="code-marker" src="/assets/s.png" />And add this `handleLogout` method to `src/App.js` above the `render() {` line as well.

``` coffee
Expand Down
86 changes: 34 additions & 52 deletions _chapters/adding-links-in-the-navbar.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ title: Adding Links in the Navbar
date: 2017-01-11 12:00:00
description: To add links to the Navbar of our React.js app we’ll be using the NavItem React-Bootstrap component. And to allow users to navigate using these links we are going to use React-Router's Route component and call the history.push method.
context: frontend
code: frontend
comments_id: 35
---

Expand Down Expand Up @@ -51,70 +50,53 @@ Now if you flip over to your browser, you should see the two links in our navbar

![Navbar links added screenshot](/assets/navbar-links-added.png)

Unfortunately, they don't do a whole lot when you click on them. We also need them to highlight when we navigate to that page. To fix this we are going to use a useful feature of the React-Router. We are going to use the `Route` component to detect when we are on a certain page and then render based on it. Since we are going to do this twice, let's make this into a component that can be re-used.
Unfortunately, when you click on them they refresh your browser while redirecting to the link. We need it to route it to the new link without refreshing the page since we are building a single page app.

<img class="code-marker" src="/assets/s.png" />Create a `src/components/` directory and add the following inside `src/components/RouteNavItem.js`.
To fix this we need a component that works with React Router and React Bootstrap called [React Router Bootstrap](https://github.com/react-bootstrap/react-router-bootstrap). It can wrap around your `Navbar` links and use the React Router to route your app to the required link without refreshing the browser.

``` coffee
import React from "react";
import { Route } from "react-router-dom";
import { NavItem } from "react-bootstrap";

export default props =>
<Route
path={props.href}
exact
children={({ match, history }) =>
<NavItem
onClick={(e) => {
e.preventDefault();
history.push(props.href);
}}
{...props}
active={match ? true : false}
>
{props.children}
</NavItem>}
/>;
```

This is doing a couple of things here:

1. We look at the `href` for the `NavItem` and check if there is a match.

2. React-Router passes in a `match` object in case there is a match. We use that and set the `active` prop for the `NavItem`.

3. React-Router also passes us a `history` object. We use this to navigate to the new page using `history.push`. We are also preventing the browser's default `anchor` on click behavior.

Now let's use this component.

<img class="code-marker" src="/assets/s.png" />Import this component in the header of our `src/App.js`.
<img class="code-marker" src="/assets/s.png" />Run the following command in your working directory.

``` coffee
import RouteNavItem from "./components/RouteNavItem";
```

<img class="code-marker" src="/assets/s.png" />And remove the `NavItem` from the header of `src/App.js`, so that the `react-bootstrap` import looks like this.

``` coffee
import { Nav, Navbar } from "react-bootstrap";
``` bash
$ npm install react-router-bootstrap --save
```

<img class="code-marker" src="/assets/s.png" />Now replace the `NavItem` components in `src/App.js`.
<img class="code-marker" src="/assets/s.png" />And include it at the top of your `src/App.js`.

``` coffee
<NavItem href="/signup">Signup</NavItem>
<NavItem href="/login">Login</NavItem>
import { LinkContainer } from "react-router-bootstrap";
```

<img class="code-marker" src="/assets/s.png" />With the following.
<img class="code-marker" src="/assets/s.png" />We will now wrap our links with the `LinkContainer`. Replace the `render` method in your `src/App.js` with this.

``` coffee
<RouteNavItem href="/signup">Signup</RouteNavItem>
<RouteNavItem href="/login">Login</RouteNavItem>
render() {
return (
<div className="App container">
<Navbar fluid collapseOnSelect>
<Navbar.Header>
<Navbar.Brand>
<Link to="/">Scratch</Link>
</Navbar.Brand>
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
<Nav pullRight>
<LinkContainer to="/signup">
<NavItem>Signup</NavItem>
</LinkContainer>
<LinkContainer to="/login">
<NavItem>Login</NavItem>
</LinkContainer>
</Nav>
</Navbar.Collapse>
</Navbar>
<Routes />
</div>
);
}
```

And that's it! Now if you flip over to your browser and click on the login link, you should see the link highlighted in the navbar.
And that's it! Now if you flip over to your browser and click on the login link, you should see the link highlighted in the navbar. Also, it doesn't refresh the page while redirecting.

![Navbar link highlighted screenshot](/assets/navbar-link-highlighted.png)

Expand Down
17 changes: 8 additions & 9 deletions _chapters/call-the-create-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
layout: post
title: Call the Create API
date: 2017-01-23 00:00:00
description: To let users create a note in our React.js app, we need to connect our form to our serverless API backend. We are going to use our API Gateway helper to make the request.
description: To let our users create a note in our React.js app, we need to connect our form to our serverless API backend. We are going to use AWS Amplify's API module for this.
context: frontend
code: frontend
comments_id: 48
---

Now that we know how to connect to API Gateway securely, let's make the API call to create our note.
Now that we have our basic create note form working, let's connect it to our API. We'll do the upload to S3 a little bit later. Our APIs are secured using AWS IAM and Cognito User Pool is our authentication provider. Thankfully, Amplify takes care of this for us by using the logged in user's session.

<img class="code-marker" src="/assets/s.png" />Let's include our `awsLib` by adding the following to the header of `src/containers/NewNote.js`.
We just need to use the `API` module that AWS Amplify has.

<img class="code-marker" src="/assets/s.png" />Let's include the `API` module by adding the following to the header of `src/containers/NewNote.js`.

``` javascript
import { invokeApig } from "../libs/awsLib";
import { API } from "aws-amplify";
```

<img class="code-marker" src="/assets/s.png" />And replace our `handleSubmit` function with the following.
Expand Down Expand Up @@ -41,17 +42,15 @@ handleSubmit = async event => {
}

createNote(note) {
return invokeApig({
path: "/notes",
method: "POST",
return API.post("notes", "/notes", {
body: note
});
}
```

This does a couple of simple things.

1. We make our create call in `createNote` by making a POST request to `/notes` and passing in our note object.
1. We make our create call in `createNote` by making a POST request to `/notes` and passing in our note object. Notice that the first two arguments to the `API.post()` method are `notes` and `/notes`. This is because back in the [Configure AWS Amplify]({% link _chapters/configure-aws-amplify.md %}) chapter we called these set of APIs by the name `notes`.

2. For now the note object is simply the content of the note. We are creating these notes without an attachment for now.

Expand Down
12 changes: 6 additions & 6 deletions _chapters/call-the-list-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
layout: post
title: Call the List API
date: 2017-01-27 00:00:00
description: To display a list of all of the user’s notes in our React.js app, we are going to make a GET request to our serverless API backend. We are also going to use the ListGroup and ListGroupItem React-Bootstrap components to render the list.
description: To display a list of all of the user’s notes in our React.js app, we are going to make a GET request to our serverless API backend using the AWS Amplify API module. We are also going to use the ListGroup and ListGroupItem React-Bootstrap components to render the list.
context: frontend
code: frontend
comments_id: 52
Expand All @@ -21,8 +21,8 @@ async componentDidMount() {
}

try {
const results = await this.notes();
this.setState({ notes: results });
const notes = await this.notes();
this.setState({ notes });
} catch (e) {
alert(e);
}
Expand All @@ -31,14 +31,14 @@ async componentDidMount() {
}

notes() {
return invokeApig({ path: "/notes" });
return API.get("notes", "/notes");
}
```

<img class="code-marker" src="/assets/s.png" />And include our API Gateway Client helper in the header.
<img class="code-marker" src="/assets/s.png" />And include our Amplify API module in the header.

``` javascript
import { invokeApig } from '../libs/awsLib';
import { API } from "aws-amplify";
```

All this does, is make a GET request to `/notes` on `componentDidMount` and puts the results in the `notes` object in the state.
Expand Down
34 changes: 0 additions & 34 deletions _chapters/clear-aws-credentials-cache.md

This file was deleted.

31 changes: 6 additions & 25 deletions _chapters/clear-the-session-on-logout.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,20 @@
layout: post
title: Clear the Session on Logout
date: 2017-01-16 00:00:00
description: We need to make sure to clear the logged in session using the Amazon Cognito JS SDK in our React.js app when the user logs out. We can do this using the signOut method.
description: We need to make sure to clear the logged in user's Amazon Cognito session in our React.js app when the user logs out. We can do this using AWS Amplify's Auth.signOut() method.
context: frontend
code: frontend
comments_id: 41
---

Currently we are only removing the user session from our app's state. But when we refresh the page, we load the user session from the browser Local Storage, in effect logging them back in.
Currently we are only removing the user session from our app's state. But when we refresh the page, we load the user session from the browser Local Storage (using Amplify), in effect logging them back in.

<img class="code-marker" src="/assets/s.png" />Let's create a `signOutUser` method and add it to our `src/libs/awsLib.js`.
AWS Amplify has a `Auth.signOut()` method that helps clear it out.

``` coffee
export function signOutUser() {
const currentUser = getCurrentUser();

if (currentUser !== null) {
currentUser.signOut();
}
}
```

Here we are using the AWS Cognito JS SDK to log the user out by calling `currentUser.signOut()`.

<img class="code-marker" src="/assets/s.png" />Next we'll include that in our `App` component. Replace the `import { authUser }` line in the header of `src/App.js` with:

``` javascript
import { authUser, signOutUser } from "./libs/awsLib";
```

<img class="code-marker" src="/assets/s.png" />And replace the `handleLogout` method in our `src/App.js` with this:
<img class="code-marker" src="/assets/s.png" />Let's replace the `handleLogout` method in our `src/App.js` with this:

``` javascript
handleLogout = event => {
signOutUser();
handleLogout = async event => {
await Auth.signOut();

this.userHasAuthenticated(false);
}
Expand Down
Loading

0 comments on commit 82ee17f

Please sign in to comment.