Deploy the APIs
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 runningserverless deploy
, it can be because of a few different issues. One of the most common is the format of the authorizer ARN in ourserverless.yml
. It needs to start witharn: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 aconsole.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 yourserverless.yml
to the one from this chapter.
If you liked this post, please subscribe to our newsletter and give us a star on GitHub.
For help and discussion
Comments on this chapterFor reference, here is the complete code
Backend Source