{"action":"created","comment":{"url":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/comments/56291291","id":56291291,"diff_hunk":"@@ -0,0 +1,127 @@\n+# Custom error codes with Lambda and API Gateway\n+\n+Combining Amazon's Lambda and API Gateway is an effective means of creating a robust and cost effective api.\n+\n+Lambda functions contains two primary methods called for success or failure but one quickly discovers  that ```context.fail()``` still returns a successful 200 response.  Ultimately both code paths below return 200.\n+\n+```js\n+exports.myHandler = function(event, context) {\n+   if (superAwesomeCode() === 'ok') {\n+     context.succeed('It worked!');\n+   } else {\n+     context.fail('There was an error')\n+   }\n+}\n+```\n+\n+This is obviously not a very helpful response for our api consumers. Fortunately Amazon has provided a solution for this (if not a slightly unusual one - but one that does lets us achieve what we need).\n+\n+### What do lambda error responses look like via the api gateway?\n+\n+Lets have a look at how failure calls from Lambda are displayed. The simple lambda code below...\n+```js\n+exports.myHandler = function(event, context) {\n+  var error = new Error(\"Invalid data\")\n+  context.fail(error)\n+}\n+```\n+...will result with the following response _(including the http status for clarity)_\n+```js\n+Status: 200\n+{\n+  \"errorMessage\": \"Invalid data\",\n+  \"errorType\": \"Error\",\n+  \"stackTrace\": [\n+    \"exports.handler (/var/task/index.js:11:17)\"\n+  ]\n+}\n+```\n+For interest the same can be achieved without using a real error object, by just calling ```context.fail(\"Invalid data\")``` resulting in...\n+```js\n+Status: 200\n+{\n+  \"errorMessage\": \"Invalid data\"\n+}\n+```\n+\n+\n+### Specifying error codes\n+\n+Our first step in achieving relevant http status codes back from our api is to tell the gateway each  code we wish to return.  From the method execution page of the API Gateway resource (below), select **Method Response** at the bottom right.\n+\n+![Local Image](./images/api-gateway-errors/gateway-method-execution.png)\n+\n+  \n+Simply click **Add response** for each of your desired status codes.\n+\n+![Local Image](./images/api-gateway-errors/gateway-response-codes.png)\n+\n+### Mapping error codes\n+\n+Next let's map these status codes to our lambda responses within the gateway. Again from method execution select **Integration Response**.  We are able to specify a regex pattern on the lambda fail response and map that to a one of our status codes we created.  It's interesting to note (and somewhat frustrating) that the regex patters match against the returned ```errorMessage``` property (whether using an error object or a string), you are in fact not able to match against the actual error type (which might sound sensible).\n+\n+Let's add the first response of 400 when invalid data is sent to our api as per the examples above.  Matching a regex against the errorMessage we can use  ```Invalid.*```\n+\n+![Local Image](./images/api-gateway-errors/gateway-regex-1.png)\n+\n+All failure calls with a message starting with \"Invalid\" will now return with a 400 status code.\n+\n+```js\n+exports.myHandler = function(event, context) {\n+  var error = new Error(\"Invalid data\")\n+  context.fail(error)\n+}\n+```\n+\n+```js\n+Status: 400\n+{\n+  \"errorMessage\": \"Invalid data\",\n+  \"errorType\": \"Error\",\n+  \"stackTrace\": [\n+    \"exports.handler (/var/task/index.js:11:17)\"\n+  ]\n+}\n+```\n+\n+It's up to you whether you prefix your error messages with predictable phrasing to match against a regex pattern, or use some more complicated regex patterns to match against a variety of responses.\n+\n+A good approach after entering several status regex patterns is to map a final _catch all_ error response for all remaining failures (the API Gateway will return the first status code it matches against).\n+\n+For the catch all error response the intuitive ```.*``` _(matching any character or nothing at all)_ will in fact match for even a ```context.succeed()```.  So instead we can use ```.+``` _(matching at least something)_ which will match for failure, but still return 200 as the default mapping for ```context.succeed()```.\n+\n+![Local Image](./images/api-gateway-errors/gateway-regex-2.png)\n+\n+```js\n+exports.myHandler = function(event, context) {\n+  var error = new Error(\"A different error\")\n+  context.fail(error)\n+}\n+```\n+will result in the below with a status code of 500!\n+```js\n+Status: 500\n+{\n+  \"errorMessage\": \"A different error\",\n+  \"errorType\": \"Error\",\n+  \"stackTrace\": [\n+    \"exports.handler (/var/task/index.js:11:17)\"\n+  ]\n+}\n+```\n+\n+### Response mapping templates\n+As a final touch let's remove the ```stackTrack``` property from our error response (as for api purposes it's more information than we may wish to provide).  One-by-one expand each regex to reveal **Mapping templates** and enter ```application/json``` (don't forget the little 'tick' to save). Clicking your newly created mapping template will show **Output passthrough** towards the right (which currently allows the full error response through).  Click the edit button next to it and select **Mapping template** from the dropdown. The below json will specify your output pulling in the original data from the response but omitting the stackTrace.","path":"technologies/lambda/api-gateway-errors.md","position":114,"original_position":114,"commit_id":"b54a7593df64c96beb6e3241925f75e30aa9aeea","original_commit_id":"b54a7593df64c96beb6e3241925f75e30aa9aeea","user":{"login":"kizza","id":1088717,"avatar_url":"https://avatars.githubusercontent.com/u/1088717?v=3","gravatar_id":"","url":"https://api.github.com/users/kizza","html_url":"https://github.com/kizza","followers_url":"https://api.github.com/users/kizza/followers","following_url":"https://api.github.com/users/kizza/following{/other_user}","gists_url":"https://api.github.com/users/kizza/gists{/gist_id}","starred_url":"https://api.github.com/users/kizza/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kizza/subscriptions","organizations_url":"https://api.github.com/users/kizza/orgs","repos_url":"https://api.github.com/users/kizza/repos","events_url":"https://api.github.com/users/kizza/events{/privacy}","received_events_url":"https://api.github.com/users/kizza/received_events","type":"User","site_admin":false},"body":"No I definitely meant stackTrack. :) Nice catch!","created_at":"2016-03-16T07:30:13Z","updated_at":"2016-03-16T07:30:13Z","html_url":"https://github.com/everydayhero/how-we-build-things/pull/6#discussion_r56291291","pull_request_url":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/6","_links":{"self":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/comments/56291291"},"html":{"href":"https://github.com/everydayhero/how-we-build-things/pull/6#discussion_r56291291"},"pull_request":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/6"}}},"pull_request":{"url":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/6","id":59901578,"html_url":"https://github.com/everydayhero/how-we-build-things/pull/6","diff_url":"https://github.com/everydayhero/how-we-build-things/pull/6.diff","patch_url":"https://github.com/everydayhero/how-we-build-things/pull/6.patch","issue_url":"https://api.github.com/repos/everydayhero/how-we-build-things/issues/6","number":6,"state":"open","locked":false,"title":"Add lambda + api gateway error status codes article","user":{"login":"kizza","id":1088717,"avatar_url":"https://avatars.githubusercontent.com/u/1088717?v=3","gravatar_id":"","url":"https://api.github.com/users/kizza","html_url":"https://github.com/kizza","followers_url":"https://api.github.com/users/kizza/followers","following_url":"https://api.github.com/users/kizza/following{/other_user}","gists_url":"https://api.github.com/users/kizza/gists{/gist_id}","starred_url":"https://api.github.com/users/kizza/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kizza/subscriptions","organizations_url":"https://api.github.com/users/kizza/orgs","repos_url":"https://api.github.com/users/kizza/repos","events_url":"https://api.github.com/users/kizza/events{/privacy}","received_events_url":"https://api.github.com/users/kizza/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-02-19T03:55:41Z","updated_at":"2016-03-16T07:30:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":"592c7b88955407cf18ce99f4cf45c1451cbe0f3d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/6/commits","review_comments_url":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/6/comments","review_comment_url":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/comments{/number}","comments_url":"https://api.github.com/repos/everydayhero/how-we-build-things/issues/6/comments","statuses_url":"https://api.github.com/repos/everydayhero/how-we-build-things/statuses/b54a7593df64c96beb6e3241925f75e30aa9aeea","head":{"label":"everydayhero:ko-add-lambda-error-codes","ref":"ko-add-lambda-error-codes","sha":"b54a7593df64c96beb6e3241925f75e30aa9aeea","user":{"login":"everydayhero","id":558383,"avatar_url":"https://avatars.githubusercontent.com/u/558383?v=3","gravatar_id":"","url":"https://api.github.com/users/everydayhero","html_url":"https://github.com/everydayhero","followers_url":"https://api.github.com/users/everydayhero/followers","following_url":"https://api.github.com/users/everydayhero/following{/other_user}","gists_url":"https://api.github.com/users/everydayhero/gists{/gist_id}","starred_url":"https://api.github.com/users/everydayhero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/everydayhero/subscriptions","organizations_url":"https://api.github.com/users/everydayhero/orgs","repos_url":"https://api.github.com/users/everydayhero/repos","events_url":"https://api.github.com/users/everydayhero/events{/privacy}","received_events_url":"https://api.github.com/users/everydayhero/received_events","type":"Organization","site_admin":false},"repo":{"id":48075954,"name":"how-we-build-things","full_name":"everydayhero/how-we-build-things","owner":{"login":"everydayhero","id":558383,"avatar_url":"https://avatars.githubusercontent.com/u/558383?v=3","gravatar_id":"","url":"https://api.github.com/users/everydayhero","html_url":"https://github.com/everydayhero","followers_url":"https://api.github.com/users/everydayhero/followers","following_url":"https://api.github.com/users/everydayhero/following{/other_user}","gists_url":"https://api.github.com/users/everydayhero/gists{/gist_id}","starred_url":"https://api.github.com/users/everydayhero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/everydayhero/subscriptions","organizations_url":"https://api.github.com/users/everydayhero/orgs","repos_url":"https://api.github.com/users/everydayhero/repos","events_url":"https://api.github.com/users/everydayhero/events{/privacy}","received_events_url":"https://api.github.com/users/everydayhero/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/everydayhero/how-we-build-things","description":null,"fork":false,"url":"https://api.github.com/repos/everydayhero/how-we-build-things","forks_url":"https://api.github.com/repos/everydayhero/how-we-build-things/forks","keys_url":"https://api.github.com/repos/everydayhero/how-we-build-things/keys{/key_id}","collaborators_url":"https://api.github.com/repos/everydayhero/how-we-build-things/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/everydayhero/how-we-build-things/teams","hooks_url":"https://api.github.com/repos/everydayhero/how-we-build-things/hooks","issue_events_url":"https://api.github.com/repos/everydayhero/how-we-build-things/issues/events{/number}","events_url":"https://api.github.com/repos/everydayhero/how-we-build-things/events","assignees_url":"https://api.github.com/repos/everydayhero/how-we-build-things/assignees{/user}","branches_url":"https://api.github.com/repos/everydayhero/how-we-build-things/branches{/branch}","tags_url":"https://api.github.com/repos/everydayhero/how-we-build-things/tags","blobs_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/refs{/sha}","trees_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/trees{/sha}","statuses_url":"https://api.github.com/repos/everydayhero/how-we-build-things/statuses/{sha}","languages_url":"https://api.github.com/repos/everydayhero/how-we-build-things/languages","stargazers_url":"https://api.github.com/repos/everydayhero/how-we-build-things/stargazers","contributors_url":"https://api.github.com/repos/everydayhero/how-we-build-things/contributors","subscribers_url":"https://api.github.com/repos/everydayhero/how-we-build-things/subscribers","subscription_url":"https://api.github.com/repos/everydayhero/how-we-build-things/subscription","commits_url":"https://api.github.com/repos/everydayhero/how-we-build-things/commits{/sha}","git_commits_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/commits{/sha}","comments_url":"https://api.github.com/repos/everydayhero/how-we-build-things/comments{/number}","issue_comment_url":"https://api.github.com/repos/everydayhero/how-we-build-things/issues/comments{/number}","contents_url":"https://api.github.com/repos/everydayhero/how-we-build-things/contents/{+path}","compare_url":"https://api.github.com/repos/everydayhero/how-we-build-things/compare/{base}...{head}","merges_url":"https://api.github.com/repos/everydayhero/how-we-build-things/merges","archive_url":"https://api.github.com/repos/everydayhero/how-we-build-things/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/everydayhero/how-we-build-things/downloads","issues_url":"https://api.github.com/repos/everydayhero/how-we-build-things/issues{/number}","pulls_url":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls{/number}","milestones_url":"https://api.github.com/repos/everydayhero/how-we-build-things/milestones{/number}","notifications_url":"https://api.github.com/repos/everydayhero/how-we-build-things/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/everydayhero/how-we-build-things/labels{/name}","releases_url":"https://api.github.com/repos/everydayhero/how-we-build-things/releases{/id}","deployments_url":"https://api.github.com/repos/everydayhero/how-we-build-things/deployments","created_at":"2015-12-15T23:58:33Z","updated_at":"2016-01-14T00:15:49Z","pushed_at":"2016-02-19T03:55:41Z","git_url":"git://github.com/everydayhero/how-we-build-things.git","ssh_url":"git@github.com:everydayhero/how-we-build-things.git","clone_url":"https://github.com/everydayhero/how-we-build-things.git","svn_url":"https://github.com/everydayhero/how-we-build-things","homepage":null,"size":312,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":3,"forks":1,"open_issues":3,"watchers":0,"default_branch":"master"}},"base":{"label":"everydayhero:master","ref":"master","sha":"caed62f8d539052f0510e4585795770305eedb3f","user":{"login":"everydayhero","id":558383,"avatar_url":"https://avatars.githubusercontent.com/u/558383?v=3","gravatar_id":"","url":"https://api.github.com/users/everydayhero","html_url":"https://github.com/everydayhero","followers_url":"https://api.github.com/users/everydayhero/followers","following_url":"https://api.github.com/users/everydayhero/following{/other_user}","gists_url":"https://api.github.com/users/everydayhero/gists{/gist_id}","starred_url":"https://api.github.com/users/everydayhero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/everydayhero/subscriptions","organizations_url":"https://api.github.com/users/everydayhero/orgs","repos_url":"https://api.github.com/users/everydayhero/repos","events_url":"https://api.github.com/users/everydayhero/events{/privacy}","received_events_url":"https://api.github.com/users/everydayhero/received_events","type":"Organization","site_admin":false},"repo":{"id":48075954,"name":"how-we-build-things","full_name":"everydayhero/how-we-build-things","owner":{"login":"everydayhero","id":558383,"avatar_url":"https://avatars.githubusercontent.com/u/558383?v=3","gravatar_id":"","url":"https://api.github.com/users/everydayhero","html_url":"https://github.com/everydayhero","followers_url":"https://api.github.com/users/everydayhero/followers","following_url":"https://api.github.com/users/everydayhero/following{/other_user}","gists_url":"https://api.github.com/users/everydayhero/gists{/gist_id}","starred_url":"https://api.github.com/users/everydayhero/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/everydayhero/subscriptions","organizations_url":"https://api.github.com/users/everydayhero/orgs","repos_url":"https://api.github.com/users/everydayhero/repos","events_url":"https://api.github.com/users/everydayhero/events{/privacy}","received_events_url":"https://api.github.com/users/everydayhero/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/everydayhero/how-we-build-things","description":null,"fork":false,"url":"https://api.github.com/repos/everydayhero/how-we-build-things","forks_url":"https://api.github.com/repos/everydayhero/how-we-build-things/forks","keys_url":"https://api.github.com/repos/everydayhero/how-we-build-things/keys{/key_id}","collaborators_url":"https://api.github.com/repos/everydayhero/how-we-build-things/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/everydayhero/how-we-build-things/teams","hooks_url":"https://api.github.com/repos/everydayhero/how-we-build-things/hooks","issue_events_url":"https://api.github.com/repos/everydayhero/how-we-build-things/issues/events{/number}","events_url":"https://api.github.com/repos/everydayhero/how-we-build-things/events","assignees_url":"https://api.github.com/repos/everydayhero/how-we-build-things/assignees{/user}","branches_url":"https://api.github.com/repos/everydayhero/how-we-build-things/branches{/branch}","tags_url":"https://api.github.com/repos/everydayhero/how-we-build-things/tags","blobs_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/refs{/sha}","trees_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/trees{/sha}","statuses_url":"https://api.github.com/repos/everydayhero/how-we-build-things/statuses/{sha}","languages_url":"https://api.github.com/repos/everydayhero/how-we-build-things/languages","stargazers_url":"https://api.github.com/repos/everydayhero/how-we-build-things/stargazers","contributors_url":"https://api.github.com/repos/everydayhero/how-we-build-things/contributors","subscribers_url":"https://api.github.com/repos/everydayhero/how-we-build-things/subscribers","subscription_url":"https://api.github.com/repos/everydayhero/how-we-build-things/subscription","commits_url":"https://api.github.com/repos/everydayhero/how-we-build-things/commits{/sha}","git_commits_url":"https://api.github.com/repos/everydayhero/how-we-build-things/git/commits{/sha}","comments_url":"https://api.github.com/repos/everydayhero/how-we-build-things/comments{/number}","issue_comment_url":"https://api.github.com/repos/everydayhero/how-we-build-things/issues/comments{/number}","contents_url":"https://api.github.com/repos/everydayhero/how-we-build-things/contents/{+path}","compare_url":"https://api.github.com/repos/everydayhero/how-we-build-things/compare/{base}...{head}","merges_url":"https://api.github.com/repos/everydayhero/how-we-build-things/merges","archive_url":"https://api.github.com/repos/everydayhero/how-we-build-things/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/everydayhero/how-we-build-things/downloads","issues_url":"https://api.github.com/repos/everydayhero/how-we-build-things/issues{/number}","pulls_url":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls{/number}","milestones_url":"https://api.github.com/repos/everydayhero/how-we-build-things/milestones{/number}","notifications_url":"https://api.github.com/repos/everydayhero/how-we-build-things/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/everydayhero/how-we-build-things/labels{/name}","releases_url":"https://api.github.com/repos/everydayhero/how-we-build-things/releases{/id}","deployments_url":"https://api.github.com/repos/everydayhero/how-we-build-things/deployments","created_at":"2015-12-15T23:58:33Z","updated_at":"2016-01-14T00:15:49Z","pushed_at":"2016-02-19T03:55:41Z","git_url":"git://github.com/everydayhero/how-we-build-things.git","ssh_url":"git@github.com:everydayhero/how-we-build-things.git","clone_url":"https://github.com/everydayhero/how-we-build-things.git","svn_url":"https://github.com/everydayhero/how-we-build-things","homepage":null,"size":312,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":3,"forks":1,"open_issues":3,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/6"},"html":{"href":"https://github.com/everydayhero/how-we-build-things/pull/6"},"issue":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/issues/6"},"comments":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/issues/6/comments"},"review_comments":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/6/comments"},"review_comment":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/pulls/6/commits"},"statuses":{"href":"https://api.github.com/repos/everydayhero/how-we-build-things/statuses/b54a7593df64c96beb6e3241925f75e30aa9aeea"}}}}