Call the List API

From @akolybelnikov on Sat Nov 11 2017 13:01:51 GMT+0000 (UTC)

@jayair what if I needed to lay one route open to not-signed in users, for example render example notes created by the admin with his access permissions? How can I bypass the sign-in functionality and send a get request to fetch data from a DynamoDB table? Do I have to create a new Iam user in order to achieve that?

From @jayair on Sat Nov 11 2017 19:47:43 GMT+0000 (UTC)

@akolybelnikov Youā€™d need to create an API without an authorizer - https://github.com/AnomalyInnovations/serverless-stack-demo-api/blob/master/serverless.yml#L69. And in the awsLib.js for the React portion, just skip signing the request and directly make a fetch call - https://github.com/AnomalyInnovations/serverless-stack-demo-client/blob/master/src/libs/awsLib.js#L17.

From @NYCSwan on Fri Feb 09 2018 17:06:47 GMT+0000 (UTC)

Hi! Iā€™m working through your tutorial and have hit a snag. Iā€™ve adapted the tutorial for the project Iā€™m working on so there are a few extra functions and db tables. I donā€™t think thatā€™s where the problem stems from after following your debugging instructions but wanted to mention that in case it is the problem. Essentially, I can invoke the api gateway fns from the terminal with ā€˜sls deployā€™ and get the correct response. However, when I try to do the same from the react app, it comes through cloudwatch but doesnā€™t pass into the app. The result var in componentWIllMount after invokeapig is ā€œ{}ā€.

I have quadruple checked that all of my files match what is in the tutorial. Followed the error in cloudwatch and it returns the correct information (garden aka note in the tutorial) with a 200 status. I have stepped through the entire app in debugger and canā€™t find where the response body comes in. I can successfully post a new garden to the db.

The awsLibs invokespig() returns this result:

Response {type: "cors", url: "https://API_GATEWAY.execute-api.us-east-1.amazonaws.com/prod/gardens", redirected: false, status: 200, ok: true, ā€¦}
The body attr is a ReadableStream.

My Notes/gardens page:

class Gardens extends Component {
  static propTypes = {
    match: PropTypes.shape({
      path: PropTypes.string
    }).isRequired,
    isAuthenticated: PropTypes.bool.isRequired
  };

  state = {
    chamberId: 1,
    chamberData: [],
    growingPlants: [],
    chambers: [],
    isLoading: true
  };

  async componentDidMount() {
    console.log('componentDidMount monitor');

    try {
      const growingResults = await this.growingPlants();
      this.setState({growingPlants: growingResults});
    } catch(e) {
      console.log(e);
    }
    this.setState({ isLoading: false });
  }

growingPlants = () => {
    console.log('get growing plants from db');
    return invokeApig({ path: "/gardens" });  // eslint-disable-line
  }

  renderGardensList(chambers) {
    return [{}].concat(gardens).map(
      (garden, i) =>
        i !== 0
          ? <ListGroupItem
              key={garden.chamberId}
              href={`/gardens/${gardens.chamberId}`}
              onClick={this.handleNoteClick}
              header={gardens.chamberName}
            >
              {"Created: " + new Date(garden.createdAt).toLocaleString()}
            </ListGroupItem>
          : <ListGroupItem
              key="new"
              href="/NewGrow"
              onClick={this.handleChamberClick}
            >
              <h4>
                <b>{"\uFF0B"}</b> Start a new Garden
              </h4>
            </ListGroupItem>
    );
  }

  handleGardenClick = event => {
    event.preventDefault();
    this.props.history.push(event.currentTarget.getAttribute("href"));
  }

  renderGardens() {
   return (
     <div className="gardens">
       <PageHeader>Your Gardens</PageHeader>
       <ListGroup>
         {!this.state.isLoading && this.renderGardensList(this.state.growingPlants)}
       </ListGroup>
     </div>
   );
 }

renderLander() {..}

render() {
  return (
      <div className="monitor container">
        {this.props.isAuthenticated ? this.renderChambers() : this.renderLander()}
      </div>
)}};

My AWS permissions for the auth_role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::MY_BUCKET/${cognito-identity.amazonaws.com:sub}*",
                "arn:aws:s3:::ANOTHER_BUCKET/${cognito-identity.amazonaws.com:sub}*",
                "arn:aws:s3:::BUCKET_FOR_MY_APP/${cognito-identity.amazonaws.com:sub}*",
                "arn:aws:s3:::DEPLOYMENT_BUCKET/${cognito-identity.amazonaws.com:sub}*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "execute-api:Invoke"
            ],
            "Resource": [
                "arn:aws:execute-api:us-east-1:*:MY_API_GATEWAY_ID/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:*"
            ],
            "Resource": [
                "arn:aws:dynamodb:us-east-1:*:table/*"
            ]
        }
    ]
}

Thanks in advance for the help and this tutorial has saved me so many hours of confusion. Itā€™s seriously one of the best Iā€™ve tried :1st_place_medal:

From @jayair on Fri Feb 09 2018 18:29:55 GMT+0000 (UTC)

@NYCSwan Hmm so you are able to write to the db but when you read from it you get an empty result with a 200 status?

It might be that the table you are writing to (with the user id) and the one you are fetching from is not the same?

From @NYCSwan on Sat Feb 10 2018 00:57:51 GMT+0000 (UTC)

@jayair You got it. I can write to the db but it returns an empty hash when I try to get or list items from a table. I found another bug when I try to get one single item. I get a 403 preflight cors issue or TypeError: body stream already read error. Iā€™m fetching and reading from the same table.

Get Method

  getGarden = () => {
    console.log('get indiv garden');
    // debugger
    return invokeApig({ path: `/gardens/${TIMESTAMP}`});
  };

Iā€™m watching the actual lambdas & API-Gateway-Execution-Logs

logs from /gardens/{id}:

...
message: 'The provided key element does not match the schema',
code: 'ValidationException',
time: 2018-02-09T22:42:51.694Z,
requestId: 'CQ2Q628G3DNR2L6MH8NHFDCV3RVXXXXO5AEMVJF66Q9ASUAAJG',
statusCode: 400,
retryable: false,
retryDelay: 5.994444151965716 }
2018-02-09T22:42:51.703Z	8f1bc406-0dea-11e8-b61e-d167a9b81557
{
    "status": false
}

END RequestId: 8f1bc406-0dea-11e8-b61e-d167a9b81557
REPORT RequestId: 8f1bc406-0dea-11e8-b61e-d167a9b81557	Duration: 155.51 ms	Billed Duration: 200 ms Memory Size: 1024 MB	Max Memory Used: 37 MB	
START RequestId: ca9dfd41-0dea-11e8-bb46-df0bb292ce1c Version: $LATEST
2018-02-09T22:44:30.899Z	ca9dfd41-0dea-11e8-bb46-df0bb292ce1c
{
    "gardenId": "049d18e0-0d96-11e8-83ad-a9620d2006bc",
    "chamberId": "Chamber 2",
    "climateId": "2",
    "userId": "us-east-1:1a372091-157f-48e9-bc27-9d664a7f7718",
    "plantName": "Kale",
    "createdAt": 1518179860859,
    "plantRecipeId": "3"
}

END RequestId: ca9dfd41-0dea-11e8-bb46-df0bb292ce1c
REPORT RequestId: ca9dfd41-0dea-11e8-bb46-df0bb292ce1c	Duration: 88.78 ms	Billed Duration: 100 ms Memory Size: 1024 MB	Max Memory Used: 37 MB	

From the api_gateway logs, Is Method: OPTIONS the issue? In the same minute/call, there are two logs to /gardens path, the top is METHOD: GET, the second is OPTIONS. I canā€™t find anything that mentions this.

(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) HTTP Method: OPTIONS, Resource Path: /gardens
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Method request path:
{}
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Method request query string:
{}
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Method request headers: {Accept=*/*, CloudFront-Viewer-Country=US, CloudFront-Forwarded-Proto=https, CloudFront-Is-Tablet-Viewer=false, origin=http://localhost:3000, CloudFront-Is-Mobile-Viewer=true, Referer=http://localhost:3000/controls/ExistingGrow, User-Agent=Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1, X-Forwarded-Proto=https, CloudFront-Is-SmartTV-Viewer=false, Host=az9ohrt4i7.execute-api.us-east-1.amazonaws.com, Accept-Encoding=gzip, deflate, br, dnt=1, access-control-request-method=GET, X-Forwarded-Port=443, X-Amzn-Trace-Id=Root=1-5a7e1adf-35b2160342d43365353cef70, Via=2.0 f564d0c1e4568b2b822f986a309f4114.cloudfront.net (CloudFront), access-control-request-headers=authorization,content-type,x-amz-date,x-amz-security-token, X-Amz-Cf-Id=j8QmzcWlIRC2h5fsRq_L237a65ZYHerqsN-kMqNg2Orxub0Pd3jO-Q==, X-Forwarded-For=68.174.1.162, 204.246.168.11, Accept-Language=en-US,en;q=0.9, CloudFront-Is-Desktop-Viewer=false}
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Method request body before transformations:
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Received response. Integration latency: 0 ms
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Endpoint response body before transformations:
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Endpoint response headers:
{}
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Method response body after transformations:
(2b11aa94-0de5-11e8-9e91-69a8d6edbe9f) Method response headers: {Access-Control-Allow-Origin=*, Access-Control-Allow-Credentials=false, Access-Control-Allow-Methods=OPTIONS,GET,POST, Access-Control-Allow-Headers=Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent, Content-Type=application/json}
(8e8be017-0dea-11e8-8f95-0f0011862800) Method request body before transformations:
(8e8be017-0dea-11e8-8f95-0f0011862800) Received response. Integration latency: 0 ms
(8e8be017-0dea-11e8-8f95-0f0011862800) Endpoint response body before transformations:
(8e8be017-0dea-11e8-8f95-0f0011862800) Endpoint response headers:
{}
(8e8be017-0dea-11e8-8f95-0f0011862800) Method response body after transformations:
(8e8be017-0dea-11e8-8f95-0f0011862800) Method response headers: {Access-Control-Allow-Origin=*, Access-Control-Allow-Credentials=false, Access-Control-Allow-Methods=OPTIONS,GET,POST, Access-Control-Allow-Headers=Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent, Content-Type=application/json}
(8e8be017-0dea-11e8-8f95-0f0011862800) Successfully completed execution
(8e8be017-0dea-11e8-8f95-0f0011862800) Method completed with status: 200

The /gardens log:

2018-02-09T22:42:50.711Z	8e95f28a-0dea-11e8-85af-757fe33d1b3a	[
{
    "gardenId": "049d18e0-0d96-11e8-83ad-a9620d2006ca",
    "chamberId": "Chamber 1",
    "climateId": "2",
    "userId": "us-east-1:1a372091-157f-48e9-bc27-9d664a7f7718",
    "plantName": "Cilantro",
    "createdAt": 1518179860846,
    "plantRecipeId": "2"
}
,
{
    "gardenId": "049d18e0-0d96-11e8-83ad-a9620d2006bc",
    "chamberId": "Chamber 2",
    "climateId": "2",
    "userId": "us-east-1:1a372091-157f-48e9-bc27-9d664a7f7718",
    "plantName": "Kale",
    "createdAt": 1518179860859,
    "plantRecipeId": "3"
}
,
{
    "gardenId": "47aede70-0dbe-11e8-9a81-b7b8232688ef",
    "chamberId": "Chamber 3",
    "climateId": "2",
    "userId": "us-east-1:1a372091-157f-48e9-bc27-9d664a7f7718",
    "plantName": "Cilantro",
    "createdAt": 1518197153239,
    "plantRecipeId": "2"
}
]
END RequestId: 8e95f28a-0dea-11e8-85af-757fe33d1b3a

From @jayair on Mon Feb 12 2018 19:54:47 GMT+0000 (UTC)

@NYCSwan This The provided key element does not match the schema is not good. It sounds like the table has not been set up properly. What does the table structure look like right now? And the query you are using to get an object?

From @jayair on Fri Mar 30 2018 22:27:56 GMT+0000 (UTC)

@mbahfauz Can you please not post the same issue in multiple threads? Also, for large code samples link to a Gist from elsewhere.

From @nuyulcore on Sat Mar 31 2018 09:03:05 GMT+0000 (UTC)

Okay @jayair thanks for your supports.

From @nelsoftcom on Wed Apr 04 2018 21:36:41 GMT+0000 (UTC)

Help Again please - When Iā€™m trying to list the notes -> getting an error - TypeMismatchError.
thank you :slight_smile:

From @jayair on Wed Apr 04 2018 22:29:42 GMT+0000 (UTC)

@nelsoftcom Can I see a screenshot of the error?

From @nelsoftcom on Thu Apr 05 2018 16:32:54 GMT+0000 (UTC)

nelsoftcom_error
@jayair Please see the error. Thanks

From @nuyulcore on Fri Apr 06 2018 07:29:57 GMT+0000 (UTC)

Hello jay, thanks for your support before, I can render image on list now. But I still got little problem. How can I get image url of every note on home page (List notes). Because I only get name of file on database, But still confuse how to get those image url on list notes.

From @jayair on Fri Apr 06 2018 18:52:54 GMT+0000 (UTC)

@nelsoftcom I think we need a bit more than that to debug it. Can you try it on Chrome and look at what shows up in the console?

From @jayair on Fri Apr 06 2018 18:53:53 GMT+0000 (UTC)

@mbahfauz If you can render it in the notes, why not return it on the list page and do the same?

From @nuyulcore on Sat Apr 07 2018 15:41:51 GMT+0000 (UTC)

I had try to render it with {Storage.get(ā€˜notes.attachmentā€™)} But I always got error, this is not react component. If you try to render array, xxxxx

From @jayair on Sat Apr 07 2018 20:13:49 GMT+0000 (UTC)

@mbahfauz Yeah you canā€™t directly use that in your component. It returns a promise and you need to set it after it returns. Notice what we do with it here - https://github.com/AnomalyInnovations/serverless-stack-demo-client/blob/master/src/containers/Notes.js#L31.

From @btotharye on Tue Apr 17 2018 01:36:40 GMT+0000 (UTC)

any idea why when I click on a note it takes me to the right ID page in the URL and I can see the console.log of the object but it always says page not found like its not loading the notes when I click them but its loading them fine in the list and creating them fine, just not loading the page when I click on a note, any idea what might be doing this? No errors in the console atm.

From @jayair on Tue Apr 17 2018 18:11:38 GMT+0000 (UTC)

@btotharye Does it fail to load when you go to the URL directly?

From @btotharye on Tue Apr 17 2018 18:17:59 GMT+0000 (UTC)

I just redid it and itā€™s fine not sure what the issue was, thanks

From @nuyulcore on Sun Apr 22 2018 07:06:33 GMT+0000 (UTC)

Anyone know how to call notes for not authorize user?
I had try with this code:
async componentDidMount() { const coins = await this.coins(); this.setState({ coins }); this.setState({ isLoading: false }); }

But got not creditentials.

Thanks