AWS amplify ReactでIAM認証付きAPI作成

前回は、ログイン画面を作成しました。
[AWS amplify Reactでログイン画面作成](https://qiita.com/hf7777hi/items/004b00bb23123ffd805b)

今回はIAM認証付きAPIを作成したいと思います。


# 1. API作成
構成としては、
API Gateway + Lambda + DynamoDB
で作成します。

今回は、認証済み以外のユーザからはAPIを叩けないようにします。


RESTApiを作成します。
authと比べて設定量が多いです。

amplify add api コマンドで作成できます。
以下で実行しました。

```
$ amplify add api
? Please select from one of the below mentioned services: REST  ★★
? Provide a friendly name for your resource to be used as a label for this category in the project: mytodo  ★★
? Provide a path (e.g., /items) /todo  ★★
? Choose a Lambda source Create a new Lambda function  ★★
? Provide a friendly name for your resource to be used as a label for this category in the project: mytodo8b8a2498  ★★

? Provide the AWS Lambda function name: mytodo8b8a2498  ★★
? Choose the function template that you want to use: CRUD function for Amazon DynamoDB table (Integration with Amazon API Gateway and Amazon DynamoDB)  ★★
? Choose a DynamoDB data source option Create a new DynamoDB table  ★★

Welcome to the NoSQL DynamoDB database wizard
This wizard asks you a series of questions to help determine how to set up your NoSQL database table.

? Please provide a friendly name for your resource that will be used to label this category in the project: mytodo  ★★


? Please provide table name: mytodo  ★★

##
## * DynamoDBの設定
##     * username: String: PrimaryKey
##     * todo: String
##     * status: Number
##     * timestamp: Number: SortKey
##
You can now add columns to the table.
? What would you like to name this column: username
? Please choose the data type: string
? Would you like to add another column? Yes
? What would you like to name this column: todo
? Please choose the data type: string
? Would you like to add another column? Yes
? What would you like to name this column: status
? Please choose the data type: number
? Would you like to add another column? Yes
? What would you like to name this column: timestamp
? Please choose the data type: number
? Would you like to add another column? No

Before you create the database, you must specify how items in your table are uniquely organized. You do this by specifying a primary key. The primary key uniquely identifies each item in the table so that no two items can have t
he same key. This can be an individual column, or a combination that includes a primary key and a sort key.

To learn more about primary keys, see:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.PrimaryKey

? Please choose partition key for the table: username
? Do you want to add a sort key to your table? Yes
? Please choose sort key for the table: timestamp

You can optionally add global secondary indexes for this table. These are useful when you run queries defined in a
 different column than the primary key.
To learn more about indexes, see:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.SecondaryIndexes

? Do you want to add global secondary indexes to your table? No
? Do you want to add a Lambda Trigger for your Table? No
Succesfully added DynamoDb table locally
? Do you want to access other resources created in this project from your Lambda function? Yes
? Select the category auth, storage  ★★
Auth category has a resource called mytodoe4c92a67
? Select the operations you want to permit for mytodoe4c92a67 create, read, update, delete
Storage category has a resource called mytodo
? Select the operations you want to permit for mytodo create, read, update, delete

You can access the following resource attributes as environment variables from your Lambda function
var environment = process.env.ENV
var region = process.env.REGION
var authMytodoe4c92a67UserPoolId = process.env.AUTH_MYTODOE4C92A67_USERPOOLID
var storageMytodoName = process.env.STORAGE_MYTODO_NAME
var storageMytodoArn = process.env.STORAGE_MYTODO_ARN

? Do you want to edit the local lambda function now? No
Succesfully added the Lambda function locally
? Restrict API access Yes
? Who should have access? Authenticated users only
? What kind of access do you want for Authenticated users? create, read, update, delete
? Do you want to add another path? No
Successfully added resource mytodo locally

Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
```

これでpushしてあげると、作成されます。

```
amplify push
```



参考: https://aws-amplify.github.io/docs/js/react

```
get = async () => {
  console.log('calling api');
  const response = await API.get('myapi', '/items/object/1');
  alert(JSON.stringify(response, null, 2));
};
```

でgetできるようです。


```js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

import Amplify, { Auth, API } from 'aws-amplify';
import { withAuthenticator } from 'aws-amplify-react';
import awsconfig from './aws-exports';

Amplify.configure(awsconfig);

class App extends Component {
    state = { user: null };

    componentDidMount() {
        Auth.currentAuthenticatedUser()
            .then(user => this.setState({ user }))
            .catch(() => console.log("Not signed in"));
    }

    render() {
        const { user } = this.state;

        return (
            <div className="App">
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    { (user != null) && <p>{ user.attributes.email }</p> }
                    <button onClick={() => Auth.signOut()}>Sign Out</button>
                    <button onClick={this.get}>GET</button>
                </header>
            </div>
        );
    }

    get = async () => {
        console.log('calling api');
        const response = await API.get('mytodo', '/todo/1');
        alert(JSON.stringify(response, null, 2));
    };
}


const signUpConfig = {
    header: 'MyTodo SignUp',
    hideAllDefaults: true,
    defaultCountryCode: 1,
    signUpFields: [
        {
            label: 'email',
            key: 'username',
            required: true,
            displayOrder: 1,
            type: 'email'
        },
        {
            label: 'password',
            key: 'password',
            required: true,
            displayOrder: 2,
            type: 'password'
        },
    ]
}

export default withAuthenticator(App, { signUpConfig });
```

これでAPIがリクエストできるようになりました。
これでAPIの方(Lambda)を実装していけば、OKって感じですね。