{"action":"created","comment":{"url":"https://api.github.com/repos/b2io/base2.io/pulls/comments/185576016","pull_request_review_id":116987196,"id":185576016,"diff_hunk":"@@ -0,0 +1,117 @@\n+---\n+title: Aurelia Async Routing\n+author: rdunkle\n+date: \"2018-05-03T04:00:00.000Z\"\n+path: \"/2018/05/03/aurelia-async-routing\"\n+---\n+\n+We had an issue where we were sending automated emails to users that contained links pointing to a file revision, but by the time one user opened the link it was possible that another user had already created new revisions. We wanted the links that we were sending in our emails to always point to the latest revision.\n+\n+The URI for our revisions is `/revisions/x`, with `x` being that revision's ID. We decided to change the URI to point to the file's ID, `/files/x`, and then we'd lookup the latest revision ID and reroute them. Rather than creating a component for that endpoint which would perform the async call and rerouting, we wanted to use Aurelia's router.\n+\n+Using the dynamic routing [navigationStrategy](http://aurelia.io/docs/routing/configuration#dynamically-specify-route-components), I first tried setting the navigation `instruction` like this:\n+\n+```js\n+const redirectToLatestRevision = instruction => {\n+  const fileId = instruction.params.id;\n+  this.fileService\n+    .getLatestRevisionId(fileId)\n+    .then(revisionId => {\n+      instruction.config.redirect = `revisions/${revisionId}`;\n+    })\n+    .catch(() => {\n+      instruction.config.redirect = 'home';\n+    });\n+};\n+\n+config.map([\n+  {\n+    route: ['revisions/:id'],\n+    name: 'edit',\n+    moduleId: './components/edit-revision/edit-revision',\n+    title: 'Edit',\n+  },\n+  {\n+    route: ['files/:id'],\n+    name: 'latest',\n+    navigationStrategy: redirectToLatestRevision,\n+  },\n+]);\n+```\n+\n+That doesn't work, though. I get the console error: `Cannot read property 'trim' of undefined`. The documentation says, \"within the navigation strategy Aurelia requires you to configure `instruction.config` with the desired `moduleId`, `viewPorts` or `redirect`.\" It's trying to trim one of those, and isn't waiting on my async call.\n+\n+After switching it to use `async`/`await`, however, it works without any errors:\n+\n+```js\n+const redirectToLatestRevision = async instruction => {\n+  const fileId = instruction.params.id;\n+\n+  try {\n+    const revisionId = await this.fileService.getLatestRevisionId(fileId);\n+    instruction.config.redirect = `revisions/${revisionId}`;\n+  } catch (err) {\n+    instruction.config.redirect = 'home';\n+  }\n+};\n+\n+config.map([\n+  {\n+    route: ['revisions/:id'],\n+    name: 'edit',\n+    moduleId: './components/edit-revision/edit-revision',\n+    title: 'Edit',\n+  },\n+  {\n+    route: ['files/:id'],\n+    name: 'latest',\n+    navigationStrategy: redirectToLatestRevision,\n+  },\n+]);\n+```\n+\n+We went with the above code, but as you might expect, my first attempt would have worked if I'd added `async`/`await`:\n+\n+```js\n+const redirectToLatestRevision = async instruction => {\n+  const fileId = instruction.params.id;\n+  await this.fileService\n+    .getLatestRevisionId(fileId)\n+    .then(revisionId => {\n+      instruction.config.redirect = `revisions/${revisionId}`;\n+    })\n+    .catch(() => {\n+      instruction.config.redirect = 'home';\n+    });\n+};\n+```\n+\n+On a final note, I'll tell you that before I tried `async`/`await` in the `navigationStrategy`, I landed on a worse solution using [config.mapUnknownRoutes](http://aurelia.io/docs/routing/configuration#handling-unknown-routes). You can pass `mapUnknownRoutes` a function, \"which is passed the NavigationInstruction object and can decide the route dynamically\".\n+\n+It works because the function is allowed to return a `Promise` which in turn resolves a `RouteConfig` object:\n+\n+```js\n+const handleUnknownRoutes = instruction => {\n+  const homeRedirect = {\n+    redirect: '',\n+  };\n+\n+  const filesExpression = /\\/files\\/([0-9]*)/;\n+  const { 1: fileId } = instruction.fragment.match(filesExpression) || [];\n+\n+  if (fileId) {\n+    return this.fileService\n+      .getLatestRevisionId(fileId)\n+      .then(revisionId => ({\n+        redirect: `revisions/${revisionId}`,\n+      })\n+      .catch(() => homeRedirect);\n+  }\n+\n+  return homeRedirect;\n+};\n+```\n+\n+I wanted to write this article because I saw that other people had run into this same problem (<sup>[1](https://github.com/aurelia-contrib/aurelia-open-id-connect/issues/13)</sup>, <sup>[2](https://github.com/aurelia/router/issues/289#issuecomment-359452023)</sup>). I'm fine with the `async`/`await` solution, but given how `mapUnknownRoutes` works, I think it'd be reasonable for the `navigationStrategy` function to work the same way, so that we could return a `Promise` which resolves a `RouteConfig` object.","path":"_content/posts/2018-05-03-aurelia-async-routing.md","position":115,"original_position":115,"commit_id":"a19e456d00edc9924bef84a5518fb854ad521cb6","original_commit_id":"a19e456d00edc9924bef84a5518fb854ad521cb6","user":{"login":"tborres","id":2048050,"avatar_url":"https://avatars0.githubusercontent.com/u/2048050?v=4","gravatar_id":"","url":"https://api.github.com/users/tborres","html_url":"https://github.com/tborres","followers_url":"https://api.github.com/users/tborres/followers","following_url":"https://api.github.com/users/tborres/following{/other_user}","gists_url":"https://api.github.com/users/tborres/gists{/gist_id}","starred_url":"https://api.github.com/users/tborres/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tborres/subscriptions","organizations_url":"https://api.github.com/users/tborres/orgs","repos_url":"https://api.github.com/users/tborres/repos","events_url":"https://api.github.com/users/tborres/events{/privacy}","received_events_url":"https://api.github.com/users/tborres/received_events","type":"User","site_admin":false},"body":"I like the call out to other sources, but the \"I wanted to write this article because\" feels awkwardly forced. I think that the sources would be more seamless included in the article toward the top when you describe the problem. I don't think there is a need to directly state the reason that you wrote the article - the problem/solution is the reason.","created_at":"2018-05-02T17:29:26Z","updated_at":"2018-05-02T17:32:51Z","html_url":"https://github.com/b2io/base2.io/pull/315#discussion_r185576016","pull_request_url":"https://api.github.com/repos/b2io/base2.io/pulls/315","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/b2io/base2.io/pulls/comments/185576016"},"html":{"href":"https://github.com/b2io/base2.io/pull/315#discussion_r185576016"},"pull_request":{"href":"https://api.github.com/repos/b2io/base2.io/pulls/315"}}},"pull_request":{"url":"https://api.github.com/repos/b2io/base2.io/pulls/315","id":185472828,"html_url":"https://github.com/b2io/base2.io/pull/315","diff_url":"https://github.com/b2io/base2.io/pull/315.diff","patch_url":"https://github.com/b2io/base2.io/pull/315.patch","issue_url":"https://api.github.com/repos/b2io/base2.io/issues/315","number":315,"state":"open","locked":false,"title":"feat(blog): Aurelia Async Routing","user":{"login":"reeddunkle","id":11543198,"avatar_url":"https://avatars1.githubusercontent.com/u/11543198?v=4","gravatar_id":"","url":"https://api.github.com/users/reeddunkle","html_url":"https://github.com/reeddunkle","followers_url":"https://api.github.com/users/reeddunkle/followers","following_url":"https://api.github.com/users/reeddunkle/following{/other_user}","gists_url":"https://api.github.com/users/reeddunkle/gists{/gist_id}","starred_url":"https://api.github.com/users/reeddunkle/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reeddunkle/subscriptions","organizations_url":"https://api.github.com/users/reeddunkle/orgs","repos_url":"https://api.github.com/users/reeddunkle/repos","events_url":"https://api.github.com/users/reeddunkle/events{/privacy}","received_events_url":"https://api.github.com/users/reeddunkle/received_events","type":"User","site_admin":false},"body":"@tborres Let me know if I need to sanitize the code more\r\n\r\nAll feedback welcome.","created_at":"2018-05-02T15:19:00Z","updated_at":"2018-05-02T17:32:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2c0fbf1099621da40147bbfcd65fce20c502e954","assignee":{"login":"tborres","id":2048050,"avatar_url":"https://avatars0.githubusercontent.com/u/2048050?v=4","gravatar_id":"","url":"https://api.github.com/users/tborres","html_url":"https://github.com/tborres","followers_url":"https://api.github.com/users/tborres/followers","following_url":"https://api.github.com/users/tborres/following{/other_user}","gists_url":"https://api.github.com/users/tborres/gists{/gist_id}","starred_url":"https://api.github.com/users/tborres/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tborres/subscriptions","organizations_url":"https://api.github.com/users/tborres/orgs","repos_url":"https://api.github.com/users/tborres/repos","events_url":"https://api.github.com/users/tborres/events{/privacy}","received_events_url":"https://api.github.com/users/tborres/received_events","type":"User","site_admin":false},"assignees":[{"login":"tborres","id":2048050,"avatar_url":"https://avatars0.githubusercontent.com/u/2048050?v=4","gravatar_id":"","url":"https://api.github.com/users/tborres","html_url":"https://github.com/tborres","followers_url":"https://api.github.com/users/tborres/followers","following_url":"https://api.github.com/users/tborres/following{/other_user}","gists_url":"https://api.github.com/users/tborres/gists{/gist_id}","starred_url":"https://api.github.com/users/tborres/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tborres/subscriptions","organizations_url":"https://api.github.com/users/tborres/orgs","repos_url":"https://api.github.com/users/tborres/repos","events_url":"https://api.github.com/users/tborres/events{/privacy}","received_events_url":"https://api.github.com/users/tborres/received_events","type":"User","site_admin":false}],"requested_reviewers":[{"login":"csteinert","id":1918353,"avatar_url":"https://avatars1.githubusercontent.com/u/1918353?v=4","gravatar_id":"","url":"https://api.github.com/users/csteinert","html_url":"https://github.com/csteinert","followers_url":"https://api.github.com/users/csteinert/followers","following_url":"https://api.github.com/users/csteinert/following{/other_user}","gists_url":"https://api.github.com/users/csteinert/gists{/gist_id}","starred_url":"https://api.github.com/users/csteinert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/csteinert/subscriptions","organizations_url":"https://api.github.com/users/csteinert/orgs","repos_url":"https://api.github.com/users/csteinert/repos","events_url":"https://api.github.com/users/csteinert/events{/privacy}","received_events_url":"https://api.github.com/users/csteinert/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/b2io/base2.io/pulls/315/commits","review_comments_url":"https://api.github.com/repos/b2io/base2.io/pulls/315/comments","review_comment_url":"https://api.github.com/repos/b2io/base2.io/pulls/comments{/number}","comments_url":"https://api.github.com/repos/b2io/base2.io/issues/315/comments","statuses_url":"https://api.github.com/repos/b2io/base2.io/statuses/a19e456d00edc9924bef84a5518fb854ad521cb6","head":{"label":"b2io:aurelia-async-routing","ref":"aurelia-async-routing","sha":"a19e456d00edc9924bef84a5518fb854ad521cb6","user":{"login":"b2io","id":1060701,"avatar_url":"https://avatars3.githubusercontent.com/u/1060701?v=4","gravatar_id":"","url":"https://api.github.com/users/b2io","html_url":"https://github.com/b2io","followers_url":"https://api.github.com/users/b2io/followers","following_url":"https://api.github.com/users/b2io/following{/other_user}","gists_url":"https://api.github.com/users/b2io/gists{/gist_id}","starred_url":"https://api.github.com/users/b2io/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/b2io/subscriptions","organizations_url":"https://api.github.com/users/b2io/orgs","repos_url":"https://api.github.com/users/b2io/repos","events_url":"https://api.github.com/users/b2io/events{/privacy}","received_events_url":"https://api.github.com/users/b2io/received_events","type":"Organization","site_admin":false},"repo":{"id":13473085,"name":"base2.io","full_name":"b2io/base2.io","owner":{"login":"b2io","id":1060701,"avatar_url":"https://avatars3.githubusercontent.com/u/1060701?v=4","gravatar_id":"","url":"https://api.github.com/users/b2io","html_url":"https://github.com/b2io","followers_url":"https://api.github.com/users/b2io/followers","following_url":"https://api.github.com/users/b2io/following{/other_user}","gists_url":"https://api.github.com/users/b2io/gists{/gist_id}","starred_url":"https://api.github.com/users/b2io/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/b2io/subscriptions","organizations_url":"https://api.github.com/users/b2io/orgs","repos_url":"https://api.github.com/users/b2io/repos","events_url":"https://api.github.com/users/b2io/events{/privacy}","received_events_url":"https://api.github.com/users/b2io/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/b2io/base2.io","description":null,"fork":false,"url":"https://api.github.com/repos/b2io/base2.io","forks_url":"https://api.github.com/repos/b2io/base2.io/forks","keys_url":"https://api.github.com/repos/b2io/base2.io/keys{/key_id}","collaborators_url":"https://api.github.com/repos/b2io/base2.io/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/b2io/base2.io/teams","hooks_url":"https://api.github.com/repos/b2io/base2.io/hooks","issue_events_url":"https://api.github.com/repos/b2io/base2.io/issues/events{/number}","events_url":"https://api.github.com/repos/b2io/base2.io/events","assignees_url":"https://api.github.com/repos/b2io/base2.io/assignees{/user}","branches_url":"https://api.github.com/repos/b2io/base2.io/branches{/branch}","tags_url":"https://api.github.com/repos/b2io/base2.io/tags","blobs_url":"https://api.github.com/repos/b2io/base2.io/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/b2io/base2.io/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/b2io/base2.io/git/refs{/sha}","trees_url":"https://api.github.com/repos/b2io/base2.io/git/trees{/sha}","statuses_url":"https://api.github.com/repos/b2io/base2.io/statuses/{sha}","languages_url":"https://api.github.com/repos/b2io/base2.io/languages","stargazers_url":"https://api.github.com/repos/b2io/base2.io/stargazers","contributors_url":"https://api.github.com/repos/b2io/base2.io/contributors","subscribers_url":"https://api.github.com/repos/b2io/base2.io/subscribers","subscription_url":"https://api.github.com/repos/b2io/base2.io/subscription","commits_url":"https://api.github.com/repos/b2io/base2.io/commits{/sha}","git_commits_url":"https://api.github.com/repos/b2io/base2.io/git/commits{/sha}","comments_url":"https://api.github.com/repos/b2io/base2.io/comments{/number}","issue_comment_url":"https://api.github.com/repos/b2io/base2.io/issues/comments{/number}","contents_url":"https://api.github.com/repos/b2io/base2.io/contents/{+path}","compare_url":"https://api.github.com/repos/b2io/base2.io/compare/{base}...{head}","merges_url":"https://api.github.com/repos/b2io/base2.io/merges","archive_url":"https://api.github.com/repos/b2io/base2.io/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/b2io/base2.io/downloads","issues_url":"https://api.github.com/repos/b2io/base2.io/issues{/number}","pulls_url":"https://api.github.com/repos/b2io/base2.io/pulls{/number}","milestones_url":"https://api.github.com/repos/b2io/base2.io/milestones{/number}","notifications_url":"https://api.github.com/repos/b2io/base2.io/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/b2io/base2.io/labels{/name}","releases_url":"https://api.github.com/repos/b2io/base2.io/releases{/id}","deployments_url":"https://api.github.com/repos/b2io/base2.io/deployments","created_at":"2013-10-10T14:09:35Z","updated_at":"2018-04-30T20:44:02Z","pushed_at":"2018-05-02T15:19:00Z","git_url":"git://github.com/b2io/base2.io.git","ssh_url":"git@github.com:b2io/base2.io.git","clone_url":"https://github.com/b2io/base2.io.git","svn_url":"https://github.com/b2io/base2.io","homepage":"http://base2.io","size":34113,"stargazers_count":2,"watchers_count":2,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":54,"license":null,"forks":1,"open_issues":54,"watchers":2,"default_branch":"master"}},"base":{"label":"b2io:master","ref":"master","sha":"af5541d7a0fe74d02f42eff0dd4d78e80d9fa4fc","user":{"login":"b2io","id":1060701,"avatar_url":"https://avatars3.githubusercontent.com/u/1060701?v=4","gravatar_id":"","url":"https://api.github.com/users/b2io","html_url":"https://github.com/b2io","followers_url":"https://api.github.com/users/b2io/followers","following_url":"https://api.github.com/users/b2io/following{/other_user}","gists_url":"https://api.github.com/users/b2io/gists{/gist_id}","starred_url":"https://api.github.com/users/b2io/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/b2io/subscriptions","organizations_url":"https://api.github.com/users/b2io/orgs","repos_url":"https://api.github.com/users/b2io/repos","events_url":"https://api.github.com/users/b2io/events{/privacy}","received_events_url":"https://api.github.com/users/b2io/received_events","type":"Organization","site_admin":false},"repo":{"id":13473085,"name":"base2.io","full_name":"b2io/base2.io","owner":{"login":"b2io","id":1060701,"avatar_url":"https://avatars3.githubusercontent.com/u/1060701?v=4","gravatar_id":"","url":"https://api.github.com/users/b2io","html_url":"https://github.com/b2io","followers_url":"https://api.github.com/users/b2io/followers","following_url":"https://api.github.com/users/b2io/following{/other_user}","gists_url":"https://api.github.com/users/b2io/gists{/gist_id}","starred_url":"https://api.github.com/users/b2io/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/b2io/subscriptions","organizations_url":"https://api.github.com/users/b2io/orgs","repos_url":"https://api.github.com/users/b2io/repos","events_url":"https://api.github.com/users/b2io/events{/privacy}","received_events_url":"https://api.github.com/users/b2io/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/b2io/base2.io","description":null,"fork":false,"url":"https://api.github.com/repos/b2io/base2.io","forks_url":"https://api.github.com/repos/b2io/base2.io/forks","keys_url":"https://api.github.com/repos/b2io/base2.io/keys{/key_id}","collaborators_url":"https://api.github.com/repos/b2io/base2.io/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/b2io/base2.io/teams","hooks_url":"https://api.github.com/repos/b2io/base2.io/hooks","issue_events_url":"https://api.github.com/repos/b2io/base2.io/issues/events{/number}","events_url":"https://api.github.com/repos/b2io/base2.io/events","assignees_url":"https://api.github.com/repos/b2io/base2.io/assignees{/user}","branches_url":"https://api.github.com/repos/b2io/base2.io/branches{/branch}","tags_url":"https://api.github.com/repos/b2io/base2.io/tags","blobs_url":"https://api.github.com/repos/b2io/base2.io/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/b2io/base2.io/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/b2io/base2.io/git/refs{/sha}","trees_url":"https://api.github.com/repos/b2io/base2.io/git/trees{/sha}","statuses_url":"https://api.github.com/repos/b2io/base2.io/statuses/{sha}","languages_url":"https://api.github.com/repos/b2io/base2.io/languages","stargazers_url":"https://api.github.com/repos/b2io/base2.io/stargazers","contributors_url":"https://api.github.com/repos/b2io/base2.io/contributors","subscribers_url":"https://api.github.com/repos/b2io/base2.io/subscribers","subscription_url":"https://api.github.com/repos/b2io/base2.io/subscription","commits_url":"https://api.github.com/repos/b2io/base2.io/commits{/sha}","git_commits_url":"https://api.github.com/repos/b2io/base2.io/git/commits{/sha}","comments_url":"https://api.github.com/repos/b2io/base2.io/comments{/number}","issue_comment_url":"https://api.github.com/repos/b2io/base2.io/issues/comments{/number}","contents_url":"https://api.github.com/repos/b2io/base2.io/contents/{+path}","compare_url":"https://api.github.com/repos/b2io/base2.io/compare/{base}...{head}","merges_url":"https://api.github.com/repos/b2io/base2.io/merges","archive_url":"https://api.github.com/repos/b2io/base2.io/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/b2io/base2.io/downloads","issues_url":"https://api.github.com/repos/b2io/base2.io/issues{/number}","pulls_url":"https://api.github.com/repos/b2io/base2.io/pulls{/number}","milestones_url":"https://api.github.com/repos/b2io/base2.io/milestones{/number}","notifications_url":"https://api.github.com/repos/b2io/base2.io/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/b2io/base2.io/labels{/name}","releases_url":"https://api.github.com/repos/b2io/base2.io/releases{/id}","deployments_url":"https://api.github.com/repos/b2io/base2.io/deployments","created_at":"2013-10-10T14:09:35Z","updated_at":"2018-04-30T20:44:02Z","pushed_at":"2018-05-02T15:19:00Z","git_url":"git://github.com/b2io/base2.io.git","ssh_url":"git@github.com:b2io/base2.io.git","clone_url":"https://github.com/b2io/base2.io.git","svn_url":"https://github.com/b2io/base2.io","homepage":"http://base2.io","size":34113,"stargazers_count":2,"watchers_count":2,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":54,"license":null,"forks":1,"open_issues":54,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/b2io/base2.io/pulls/315"},"html":{"href":"https://github.com/b2io/base2.io/pull/315"},"issue":{"href":"https://api.github.com/repos/b2io/base2.io/issues/315"},"comments":{"href":"https://api.github.com/repos/b2io/base2.io/issues/315/comments"},"review_comments":{"href":"https://api.github.com/repos/b2io/base2.io/pulls/315/comments"},"review_comment":{"href":"https://api.github.com/repos/b2io/base2.io/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/b2io/base2.io/pulls/315/commits"},"statuses":{"href":"https://api.github.com/repos/b2io/base2.io/statuses/a19e456d00edc9924bef84a5518fb854ad521cb6"}},"author_association":"OWNER"}}
{"actor":{"display_login":"tborres"}}