Now that our APIs are complete, let’s deploy them.

Deploy

Run the following in your working directory.

$ serverless deploy

Near the bottom of the output for this command, you will find the Service Information. This has a list of the endpoints of the APIs that were created. Make a note of these endpoints as we are going to use them later while creating our frontend. We are also going to quickly test these endpoints next.

Service Information
service: notes-app-api
stage: prod
region: us-east-1
api keys:
  None
endpoints:
  POST - https://ly55wbovq4.execute-api.us-east-1.amazonaws.com/prod/notes
  GET - https://ly55wbovq4.execute-api.us-east-1.amazonaws.com/prod/notes/{id}
  GET - https://ly55wbovq4.execute-api.us-east-1.amazonaws.com/prod/notes
  PUT - https://ly55wbovq4.execute-api.us-east-1.amazonaws.com/prod/notes/{id}
  DELETE - https://ly55wbovq4.execute-api.us-east-1.amazonaws.com/prod/notes/{id}
functions:
  notes-app-api-prod-create
  notes-app-api-prod-get
  notes-app-api-prod-list
  notes-app-api-prod-update
  notes-app-api-prod-delete

Test

Now let’s test the API we just deployed. Because the API is authenticated via the Cognito User Pool, we need to obtain an identity token to include in the API request Authorization header.

First let’s generate the identity token. Replace YOUR_COGNITO_USER_POOL_ID and YOUR_COGNITO_APP_CLIENT_ID with the values from the Create a Cognito user pool chapter. Also use the username and password of the user created in the Create a Cognito test user chapter.

And run the following.

aws cognito-idp admin-initiate-auth \
  --region us-east-1 \
  --user-pool-id YOUR_COGNITO_USER_POOL_ID \
  --client-id YOUR_COGNITO_APP_CLIENT_ID \
  --auth-flow ADMIN_NO_SRP_AUTH \
  --auth-parameters USERNAME=admin@example.com,PASSWORD=Passw0rd!

The identity token can be found in the IdToken field of the response.

{
    "AuthenticationResult": {
        "ExpiresIn": 3600, 
        "IdToken": "eyJraWQiOiIxeVVnNXQ3NWY3YzlzYlpnNURZZWFDVWhGMVhEOEdUUEpNXC9zQVhDZEhFbz0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI3MDM4MDg1Mi1iZGNiLTQ5NzAtOTU2Zi1kZTZkMGFjODBjODUiLCJhdWQiOiIxMnNyNTBwZzF1ZjAwNDRhajYzZTRoc2g2aSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE0ODc1NDUzNzUsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbVwvdXMtZWFzdC0xX1dkSEVHQWk4TyIsImNvZ25pdG86dXNlcm5hbWUiOiJmcmFuayIsImV4cCI6MTQ4NzU0ODk3NSwiaWF0IjoxNDg3NTQ1Mzc1LCJlbWFpbCI6IndhbmdmYW5qaWVAZ21haWwuY29tIn0.d7HRBs2QegvQsGwQhJfpJBWYdh9N6CwoQFhmC91ugJ0YFxVdRhHUFQl4uoLplrOJO90PjTrjmxR7az17MfRlfu8v-ij3s31oaQqz8IdWECuhWW63xCNfGMN8lAbnUBwlHISer9CIGmdf8iF-xar2uyHeH8WHhIjI3gbJw15ORCC6Fo43CuKJ6k2zWaOywMkNr7oT2U7Etk93b2pDwIgeZ4V6uGbHgv3IRJYXYvMdIqsemoF8tLpx3XD58Iq8hNJlw_gOpOp8dlpDA3AK9-vjyXYDjJ_0zZa6alf6j0XEgwCVm08IIcYhF8ntg7ju0ZVBbQwYrdgzBCBhxtfzz1elVg", 
        "RefreshToken": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.LHH4qcesrzfF5mRi3wuykgn_1Kw-rwYjiaP459Lcingf86LkYX-zL9ZZ-jKMFELbyjnXr83P7VDdNIlZCMIFOX4djp4rVU22N3tu02-xunaACSaS6oa_5j-UTcH_2dTFN5yWYkk8VyG5UQUvDYRsmblrTrLshuG9gGhwkQRVYqTP631Zt3N5TqE-YseC211_JcEcGtN_UTxq4Rjc_b2Hh7lQVZrPIKX-7ZTfcQB1QrCTseNRI2aXl6DZFqdBGSRsfpZG4lVyjCWGELT23MreX5kp8rbRhIJzPJMGSD41GdvRjzD24fOqWAp4hg1lYsJKvN1NmCjPUfsrQOohZooOiQ.FXMEC5WtcKW1Sa2h.gfvDrbzFhUboXLhKnqjIBmoTb3YkqdRc8VJuCRsNTMXGr_R5_IgTlwagesd_2ARA50DibEEX5HdfOy8sugE0QnLiGc-DLhSPmvlgTKUiz8Dbm158vBZpK8-Ps5iSp7wiZvkZvW0GzhR8v3Toyp6I_gapDlIqV3RTj34AXTbX3-3jNPitB374Pvy3yVibkhO9WPuUmFDw3AP0x1xcWjw3j8gDY_l3Hs_HyVf4con0gk17DYOqNJIgCV5dR38n2MNNY718MXmivqpFTevg4Kx0AaFPNBbixRNLlIhGbKURo3KPirUGdS_bmU4fC3p_y1xPT8qs8l-2mXT_t1XEpMQDyAF_uRKGQwNifyz-GyeuXE8hNr_32zMJEDDKRD6cP5JvfCAt--gGKIWlYfbt2e3KbG7KMnbflCTdHFvGWNa0G49Y7LUU7IebfTbuX2R8XJLi5uE3GkSSuSp3FL4aqdA1qnBOQnN7ui37BMI9vsZMRQvyYTVynQJk5wBAD59QPVPiKQocknGqeEBTKhg84vNemL9ArZYTQcxnOg-kN6Wsi9wlWoU5Q8kpsHnuEEIqRyTROcXZ4z-6Fx_S3nFVA2VBcNKA4gH9ZzsWz1N1hswFmTaeDR12PkKNVgZgXdepGoT7D8Xe3AmLtEK4Szaen1PeYEcK0VjVpglLFYMOv49a25JxU-PjcT4rA35FQ-vrSau4FHYZRDoaUi_vcZL87pjwd1OLo7pFTzJf45k_sVTl3KPasOGaHdxdC1Q6aGr9m1vTNrgy2_unqH1u4Zgrv_vyj3KlcwWkUvNlBohE-GBh4LCgeq9Piz-rq0pUOuIRheCHKgLWOu64u128pXvjvtPu-uvFwHZ9dsRQNOYEwABTI9uKgZd4hpYLVzrTSm0Y3-DS0MCnfCq5fq25PBFUfTu5XdbDt1hkCubKyw-MRHalVgZ7xlQ8HO-z7UdqHrc-JGJU40cUv6MUAq4UFdZcXkSeZdEtFj3Ww7Ck1fawNIDULzoc4ioBXJIHa7ibIVdNICU5Vv6I6d2GgAtbx5imxXXxqfvW3jqAdsTxBc9Y5c13MhTLmCrBUH33_Hya85pMqZak1uY9DQ8jgzbhSvlTZxp5rRf9p2dhPUSdr2MphN7VFOMm7cD5Fn2dseaQSjZI2wDw7A.sDAeL_Qo_PygnfFZsrk7JQ", 
        "TokenType": "Bearer", 
        "AccessToken": "eyJraWQiOiJlXC9DY3dwSjdOeWZFdk9OWXZhMmttQzdycENqRG9Rb1NKYXFaNURraldMdz0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI3MDM4MDg1Mi1iZGNiLTQ5NzAtOTU2Zi1kZTZkMGFjODBjODUiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6ImF3cy5jb2duaXRvLnNpZ25pbi51c2VyLmFkbWluIiwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tXC91cy1lYXN0LTFfV2RIRUdBaThPIiwiZXhwIjoxNDg3NTQ4OTc1LCJpYXQiOjE0ODc1NDUzNzUsImp0aSI6ImVjNjcxNzBlLTUwNzUtNDg4Yi04ZDhkLTdlNGYwYzkzMjcyOSIsImNsaWVudF9pZCI6IjEyc3I1MHBnMXVmMDA0NGFqNjNlNGhzaDZpIiwidXNlcm5hbWUiOiJmcmFuayJ9.GOcqDC2PMJdoIdCcvaG8a7GinZWGM-LwRKs98Ck-iLGkdxx3hfHK7AfaxTAE8QeP3MXoLJ0A-EwhNUofEJRhHA-R0cAsTBCmHUuIP2VLoBKSnUBFLnFojCkBoQDHE30aJ-HwIlxM9ExACDAnt6c58T3t8ALihdevUxstjRutBGJgYc-xQhXBJAqEZ0Ov7gu6-js4i070pnIEaS-NxfDIGNDqfE5tvQkglXN_RBezsnufrwFKYTqTRMeCweJE287X6-UCcTgZY16GZw8SVqik9LqbXfO9lufo3W6vkDU-fEwNat1Q-S2iKXwK-Ew2e6mQZHOHxHcw2RQ709Z_iDv3mw"
    }, 
    "ChallengeParameters": {}
}

Now we can use that as the Authorization header to make a request to our API (at the POST endpoint returned after running serverless deploy above) using the following. Replace the URL with the POST endpoint from above.

$ curl https://ly55wbovq4.execute-api.us-east-1.amazonaws.com/prod/notes \
  -H "Authorization:eyJraWQiOiIxeVVnNXQ3NWY3YzlzYlpnNURZZWFDVWhGMVhEOEdUUEpNXC9zQVhDZEhFbz0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI3MDM4MDg1Mi1iZGNiLTQ5NzAtOTU2Zi1kZTZkMGFjODBjODUiLCJhdWQiOiIxMnNyNTBwZzF1ZjAwNDRhajYzZTRoc2g2aSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE0ODc1NDUzNzUsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbVwvdXMtZWFzdC0xX1dkSEVHQWk4TyIsImNvZ25pdG86dXNlcm5hbWUiOiJmcmFuayIsImV4cCI6MTQ4NzU0ODk3NSwiaWF0IjoxNDg3NTQ1Mzc1LCJlbWFpbCI6IndhbmdmYW5qaWVAZ21haWwuY29tIn0.d7HRBs2QegvQsGwQhJfpJBWYdh9N6CwoQFhmC91ugJ0YFxVdRhHUFQl4uoLplrOJO90PjTrjmxR7az17MfRlfu8v-ij3s31oaQqz8IdWECuhWW63xCNfGMN8lAbnUBwlHISer9CIGmdf8iF-xar2uyHeH8WHhIjI3gbJw15ORCC6Fo43CuKJ6k2zWaOywMkNr7oT2U7Etk93b2pDwIgeZ4V6uGbHgv3IRJYXYvMdIqsemoF8tLpx3XD58Iq8hNJlw_gOpOp8dlpDA3AK9-vjyXYDjJ_0zZa6alf6j0XEgwCVm08IIcYhF8ntg7ju0ZVBbQwYrdgzBCBhxtfzz1elVg" \
  -d "{\"content\":\"hello world\",\"attachment\":\"hello.jpg\"}"

If the curl command is successful, the response will look similar to this.

{
  "userId": "2aa71372-f926-451b-a05b-cf714e800c8e",
  "noteId": "578eb840-f70f-11e6-9d1a-1359b3b22944",
  "content": "hello world",
  "attachment": "hello.jpg",
  "createdAt": 1487555594691
}

And that’s it for the backend! Next we are going to move on to creating the frontend of our app.


Common Issues

  • Deploy failed Unable to parse HTTP response content

    If you see Unable to parse HTTP response content while running serverless deploy, it can be because of a few different issues. One of the most common is the format of the authorizer ARN in our serverless.yml. It needs to start with arn:aws.

    Make sure it looks like this.

    authorizer:
      arn: arn:aws:cognito-idp:us-east-1:xxxxxxxxxxxx:userpool/us-east-1_XXxxXXxxx
    

    And not like this.

    authorizer:
      arn: aws:cognito-idp:us-east-1:xxxxxxxxxxxx:userpool/us-east-1_XXxxXXxxx
    
  • Response {"status":false}

    If your deploy is successful but the curl command fails with the {"status":false} response; we can do a few things to debug this. This response is generated by our handler functions when there is an error. Add a console.log like so in your handler function.

    catch(e) {
      console.log(e);
      callback(null, failure({status: false}));
    }
    

    And deploy it using serverless deploy. But we can’t see this output when we curl it, since the console logs are not sent in our HTTP responses. We need to check the logs to see this. Head over to your AWS Console > CloudWatch > click Logs in the sidebar > select the Log Group named /aws/lambda/notes-app-api-prod-create > and expand the events. This should give you an idea of the error and help you debug it.

    A common source of errors here is an improperly indented serverless.yml. Make sure to double-check the indenting in your serverless.yml to the one from this chapter.