{"@attributes":{"version":"2.0"},"channel":{"title":"Bessey's Blog","description":"Technical blog of a full stack software engineer, working on all things web since 2013","link":"https:\/\/bessey.dev\/","pubDate":"Wed, 19 Jun 2024 09:20:06 +0000","lastBuildDate":"Wed, 19 Jun 2024 09:20:06 +0000","generator":"Jekyll v3.9.5","item":[{"title":"Github Releases are no match for CHANGELOG.md","description":"<p>I have noticed a trend recently of library authors abandoning their <a href=\"https:\/\/keepachangelog.com\/en\/1.1.0\/\">CHANGELOG.md<\/a> files, in favour of Github Releases.<\/p>\n\n<p><img src=\"\/images\/changelog\/move-to-releases.png\" alt=\"Example of Github repository changelog.md stating that &quot;Release notes are now stored in Github Releases&quot;\" \/><\/p>\n\n<p>For a library author, the choice is understandable. A Github Release message contains much the same information as a changelog, so why duplicate effort and risk having no source of truth by maintaining both? But there\u2019s a pretty big problem with this: Github Releases today sucks UX wise for your library\u2019s <strong>users<\/strong>.<\/p>\n\n<p><em><strong>TLDR?<\/strong> Get the best of both worlds by generating your changelog from your Releases with <a href=\"https:\/\/github.com\/rhysd\/changelog-from-release\"><strong>rhysd\/changelog-from-release<\/strong><\/a>!<\/em><\/p>\n\n<!-- more -->\n\n<p>First off, let me clarify what I use changelogs for, and what I expect of them. By far the most common use case I have for a changelog is when upgrading a library, to understand what significant (<a href=\"https:\/\/xkcd.com\/1172\/\">to me<\/a>) changes have occurred between the version I\u2019m on and the version I\u2019m upgrading to.<\/p>\n\n<p>Pretty simple stuff, but let\u2019s see how the difficulty of completing this task differs between Github Releases and a CHANGELOG.md file.<\/p>\n\n<h3 id=\"github-releases\">Github Releases<\/h3>\n\n<p>We navigate to our repository\u2019s Releases page, where we can see the 10 most recently released versions. Most of them are patches, so we only get one minor release on the whole page.<\/p>\n\n<p><img src=\"\/images\/changelog\/releases-index.png\" alt=\"\" \/><\/p>\n\n<p>This isn\u2019t the version we\u2019re upgrading from though, obviously. It\u2019s ok though, there\u2019s a search bar, so we can just search for my exact version! Except\u2026<\/p>\n\n<p><img src=\"\/images\/changelog\/releases-bad-search.png\" alt=\"\" \/><\/p>\n\n<p>Nope, the Releases search bar behaviour is\u2026 <em>unintuitive<\/em>. Passing the exact Release tag string doesn\u2019t guarantee it comes up first, or even on the first page. Adding quotation marks doesn\u2019t either. It <a href=\"https:\/\/docs.github.com\/en\/repositories\/releasing-projects-on-github\/searching-a-repositorys-releases#search-syntax-for-searching-releases-in-a-repository\">turns out<\/a> the magic incantation is <code class=\"language-plaintext highlighter-rouge\">tag:blah<\/code>:<\/p>\n\n<p><img src=\"\/images\/changelog\/releases-search-better.png\" alt=\"\" \/><\/p>\n\n<p>Great! We have the version we\u2019re running now. Now we just need to page forwards through the newer versions. Except, that is not possible from this view:<\/p>\n\n<p><img src=\"\/images\/changelog\/releases-search-no-pager.png\" alt=\"\" \/><\/p>\n\n<p>So I guess we\u2019ll have to return to the index page, and page backwards from the latest version all the way to the version we are currently on after all. In batches of 10. Fun.<\/p>\n\n<p><img src=\"\/images\/changelog\/releases-pager.png\" alt=\"\" \/><\/p>\n\n<p>Well this is awful. Oh, at least there\u2019s a <code class=\"language-plaintext highlighter-rouge\">&amp;page=X<\/code> query param. We can use that to skip back and forth through pages homing in on the page featuring our version. We go to <code class=\"language-plaintext highlighter-rouge\">page=3<\/code> and the last version is too new. On <code class=\"language-plaintext highlighter-rouge\">page=8<\/code> the first version is too old. How about <code class=\"language-plaintext highlighter-rouge\">page=5<\/code>? Last version too new again\u2026 <strong>Somehow we have gone from upgrading a library to executing a human powered binary search<\/strong> \ud83e\udd22.<\/p>\n\n<p>Eventually we find the right page, and can now start paging forwards through the newer versions, studying the associated notes. Even now though we run into an annoying behaviour we need to be aware of. Since releases are ordered chronologically by <strong>publish<\/strong> date there may be releases \u201cbetween\u201d versions in the list that do not apply to us because they are not present in the version we are running, because they are from another branch:<\/p>\n\n<p><img src=\"\/images\/changelog\/releases-out-of-order.png\" alt=\"\" \/><\/p>\n\n<p>Mercifully it is possible to suppress pre-releases with <code class=\"language-plaintext highlighter-rouge\">prerelease:false<\/code> in the search UI. However, this doesn\u2019t solve the issue where older major versions are maintained alongside newer versions as is common for bigger dependencies like languages and frameworks. In those cases, you just have to skip past these versions.<\/p>\n\n<p>All in all, quite the ordeal to complete a seemingly simple task. So how does this <em>modern clean solution<\/em> compare to the <em>ancient archaic text file<\/em> approach?<\/p>\n\n<h3 id=\"changelogmd\">CHANGELOG.md<\/h3>\n\n<p>We navigate to our repository\u2019s CHANGELOG.md in its root directory, where we can see all versions ever. Next, we <code class=\"language-plaintext highlighter-rouge\">Ctrl+F<\/code> for our version, type its name into the browser find in page UI, and we are instantly scrolled down to it. If you prefer mice to keyboards, we also have a list of jump links to every version.<\/p>\n\n<p><img src=\"\/images\/changelog\/changelog-ctrl-f.png\" alt=\"\" \/><\/p>\n\n<p>It\u2019s not uncommon to have the entire repository\u2019s history in this single page. <a href=\"https:\/\/github.com\/facebook\/react\/blob\/4ddff7355f696ec693c5ce2bda4e7707020c3510\/CHANGELOG.md#030-may-29-2013\">React<\/a> for example has <strong>11 years of history<\/strong> on this one page.<\/p>\n\n<p>And to see changes between the upgraded version and ours? Scroll up. That\u2019s it \ud83d\ude04. By virtue of being branch specific, changelogs sidestep the aforementioned pre-release problem, because the repository\u2019s trunk branch changelog only contains changes that have landed on the trunk. If you <em>are<\/em> a pre-release tester, the release branch\u2019s changelog has what you need.<\/p>\n\n<hr \/>\n\n<p>I think the UX chasm between these two workflows is obvious, and that is why I am surprised and concerned to see CHANGELOG.md falling out of fashion. So what\u2019s to be done? Well on the off chance you are a Github employee, please, improve this experience! If Releases are to replace changelogs, as I think they reasonably could, their UX needs to be <em>better<\/em> than changelogs, not worse. A UI to see changelogs between releases X and Y would be a game changer.<\/p>\n\n<p>However, in the much likelier event you are a repo maintainer that\u2019s all in on Github Releases, please consider <strong>maintaining a CHANGELOG.md<\/strong> also. If that\u2019s too much effort consider <strong>generating a CHANGELOG.md from your existing Github Releases<\/strong>. Thanks to <a href=\"https:\/\/github.com\/rhysd\/changelog-from-release\"><strong>rhysd\/changelog-from-release<\/strong><\/a> this is a pretty simple thing to do. It can even be configured to ignore certain releases, enabling you to e.g. exclude pre-releases from your trunk changelog, but include them on your pre-release branch changelog.<\/p>\n\n<p>Thanks for reading, and above all, much love to all open source maintainers out there! \u2764\ufe0f<\/p>\n\n<p><em>PS I used to have Disqus comments on but going forward I\u2019m disabling them as they are full of really tasteless ads. Please discuss on HN \/ Reddit \/ <del>Twitter<\/del> X instead.<\/em><\/p>\n","pubDate":"Tue, 18 Jun 2024 13:01:00 +0000","link":"https:\/\/bessey.dev\/blog\/2024\/06\/18\/github-releases-vs-changelogs\/","guid":"https:\/\/bessey.dev\/blog\/2024\/06\/18\/github-releases-vs-changelogs\/","category":["changelog","github","ux"]},{"title":"Why, after 6 years, I\u2019m over GraphQL","description":"<p>GraphQL is an incredible piece of technology that has captured a lot of mindshare since I first started slinging it in production in 2018. You won\u2019t have to look far back on this (rather inactive) blog to see I have previously championed this technology. After building many a React SPA on top of a hodge podge of untyped JSON REST APIs, I found GraphQL a breath of fresh air. I was truly a GraphQL hype train member.<\/p>\n\n<p>However, as the years have gone on and I have had the opportunity to deploy to environments where non functional requirements like security, performance, and maintainability were more of a concern, my perspective has changed. In this article I would like to take you through why today, <strong>I would not recommend GraphQL to most people<\/strong>, and what I think are better alternatives.<\/p>\n\n<!-- more -->\n\n<p>Throughout I will use Ruby code with the excellent <a href=\"https:\/\/graphql-ruby.org\/\">graphql-ruby<\/a> library for examples, but I believe many of these problems are ubiquitous across choice of language \/ GraphQL library.<\/p>\n\n<p>If you know of better solutions and mitigations, please do leave a comment. Now, lets begin\u2026<\/p>\n\n<h2 id=\"attack-surface\">Attack surface<\/h2>\n\n<p>It was obvious from GraphQL\u2019s beginning that exposing a <strong>query language<\/strong> to untrusted clients increases the attack surface of the application. Nevertheless, the variety of attacks to consider was even broader than I imagined, and mitigating them is quite a burden. Here\u2019s the worst I\u2019ve had to deal with over the years\u2026<\/p>\n\n<h3 id=\"authorisation\">Authorisation<\/h3>\n\n<p>I think this is the most widely understood risk of GraphQL, so I won\u2019t go into too much depth here. TLDR: if you expose a fully self documenting query API to all clients, you better be damn sure that <strong>every field<\/strong> is authorised against the current user appropriately to the context in which that field is being fetched. Initially authorising <strong>objects<\/strong> seems like enough, but this quickly becomes insufficient. For example, say we are the <del>Twitter<\/del> X \ud83d\ude44 API:<\/p>\n\n<div class=\"language-graphql highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">query<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"n\">user<\/span><span class=\"p\">(<\/span><span class=\"n\">id<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">321<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"n\">handle<\/span><span class=\"w\"> <\/span><span class=\"c\"># \u2705 I am allowed to view Users public info<\/span><span class=\"w\">\n    <\/span><span class=\"n\">email<\/span><span class=\"w\"> <\/span><span class=\"c\"># \ud83d\uded1 I shouldn't be able to see their PII just because I can view the User<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"n\">user<\/span><span class=\"p\">(<\/span><span class=\"n\">id<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">123<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"n\">blockedUsers<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"c\"># \ud83d\uded1 And sometimes I shouldn't even be able to see their public info,<\/span><span class=\"w\">\n      <\/span><span class=\"c\"># because context matters!<\/span><span class=\"w\">\n      <\/span><span class=\"n\">handle<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre><\/div><\/div>\n\n<p>One wonders how much GraphQL holds responsibility for Broken Access Control climbing to the <a href=\"https:\/\/owasp.org\/Top10\/\">OWASP Top 10\u2019s #1 spot<\/a>. One mitigation here is to make your API secure by default by integrating with <a href=\"https:\/\/graphql-ruby.org\/authorization\/authorization\">your GraphQL library\u2019s authorisation framework<\/a>. Every object returned and\/or field resolved, your authorisation system is called to confirm that the current user has access.<\/p>\n\n<p>Compare this to the REST world where generally speaking you would authorise <strong>every endpoint<\/strong>, a far smaller task.<\/p>\n\n<h3 id=\"rate-limiting\">Rate limiting<\/h3>\n\n<p>With GraphQL we cannot assume that all requests are equally hard on the server. There is no limit to how big a query can be. Even in a completely empty schema, the types exposed for <a href=\"https:\/\/graphql.org\/learn\/introspection\/\">introspection<\/a> are cyclical, so its possible to craft a valid query that returns MBs of JSON:<\/p>\n\n<div class=\"language-graphql highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">query<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"n\">__schema<\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"n\">types<\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"n\">__typename<\/span><span class=\"w\">\n      <\/span><span class=\"n\">interfaces<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n        <\/span><span class=\"n\">possibleTypes<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n          <\/span><span class=\"n\">interfaces<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n            <\/span><span class=\"n\">possibleTypes<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n              <\/span><span class=\"n\">name<\/span><span class=\"w\">\n            <\/span><span class=\"p\">}<\/span><span class=\"w\">\n          <\/span><span class=\"p\">}<\/span><span class=\"w\">\n        <\/span><span class=\"p\">}<\/span><span class=\"w\">\n      <\/span><span class=\"p\">}<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre><\/div><\/div>\n\n<p>I just tested this attack against a <strong>very<\/strong> popular website\u2019s GraphQL API explorer and got a 500 response back after 10 seconds. I just ate 10 seconds of someone\u2019s CPU time running this (whitespace removed) <strong>128 byte<\/strong> query, and it doesn\u2019t even require me to be logged in.<\/p>\n\n<p>A common mitigation<sup id=\"fnref:1\" role=\"doc-noteref\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup> for this attack is to<\/p>\n\n<ol>\n  <li>Estimate the complexity of resolving <strong>every single field in the schema<\/strong>, and abandon queries that exceed some maximum complexity value<\/li>\n  <li>Capture the actual complexity of the run query and take it out of bucket of credits that resets at some interval<\/li>\n<\/ol>\n\n<p>This calculation is a <a href=\"https:\/\/graphql-ruby.org\/queries\/complexity_and_depth#prevent-complex-queries\">delicate affair to get right<\/a>. It gets particularly tricky when you are returning list fields whose length is not known prior to execution. You can make an assumption about the complexity of these, but if you are wrong, you may end up rate limiting valid queries or not rate limiting invalid queries.<\/p>\n\n<p>To make matters worse, its common for the graph that makes up the schema to contain cycles. Lets say you run a blog with Articles which each have multiple Tags, from which you can see associated Articles.<\/p>\n\n<div class=\"language-graphql highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">type<\/span><span class=\"w\"> <\/span><span class=\"n\">Article<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"n\">title<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"nb\">String<\/span><span class=\"w\">\n  <\/span><span class=\"n\">tags<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">Tag<\/span><span class=\"p\">]<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"k\">type<\/span><span class=\"w\"> <\/span><span class=\"n\">Tag<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"n\">name<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"nb\">String<\/span><span class=\"w\">\n  <\/span><span class=\"n\">relatedTags<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">Tag<\/span><span class=\"p\">]<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre><\/div><\/div>\n\n<p>When estimating the complexity of <code class=\"language-plaintext highlighter-rouge\">Tag.relatedTags<\/code>, you might assume that an article will never have more than 5 tags, so you set this fields complexity to <strong>5<\/strong> (or 5 * <a href=\"https:\/\/graphql-ruby.org\/queries\/complexity_and_depth#how-complexity-scoring-works\">its children\u2019s complexity<\/a>). The problem here is that <code class=\"language-plaintext highlighter-rouge\">Article.relatedTags<\/code> can be its own child, so your estimate\u2019s inaccuracy can compound exponentially. The formula is <code class=\"language-plaintext highlighter-rouge\">N^5 * 1<\/code>. So given this query:<\/p>\n\n<div class=\"language-graphql highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">query<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"n\">tag<\/span><span class=\"p\">(<\/span><span class=\"n\">name<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"security\"<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"n\">relatedTags<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"n\">relatedTags<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n        <\/span><span class=\"n\">relatedTags<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n          <\/span><span class=\"n\">relatedTags<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n            <\/span><span class=\"n\">relatedTags<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"n\">name<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span><span class=\"w\">\n          <\/span><span class=\"p\">}<\/span><span class=\"w\">\n        <\/span><span class=\"p\">}<\/span><span class=\"w\">\n      <\/span><span class=\"p\">}<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre><\/div><\/div>\n<p>You expect a complexity of <code class=\"language-plaintext highlighter-rouge\">5^5 = 3,125<\/code>. If an attacker is able to find an Article with 10 tags, they can trigger a query with a \u201ctrue\u201d complexity of <code class=\"language-plaintext highlighter-rouge\">10^5 = 100_000<\/code>, <strong>20x<\/strong> greater than estimated.<\/p>\n\n<p>A partial mitigation here is to <a href=\"https:\/\/graphql-ruby.org\/queries\/complexity_and_depth#prevent-deeply-nested-queries\">prevent deeply nested queries<\/a>. However, the example above demonstrates that this is not really a defense, as it\u2019ts not an unusually deep query. GraphQL Ruby\u2019s default maximum depth is <strong>13<\/strong>, this is just 7.<\/p>\n\n<p>Compare this to rate limiting a REST endpoint, which generally have comparable response times. In this case all you need is a bucketed rate limiter that prevents a user exceeding, say, 200 requests per minute across all endpoints. If you <strong>do<\/strong> have slower endpoints (say, a CSV report or PDF generator) you can define more aggressive rate limits for these. With some HTTP middleware this is pretty trivial:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"no\">Rack<\/span><span class=\"o\">::<\/span><span class=\"no\">Attack<\/span><span class=\"p\">.<\/span><span class=\"nf\">throttle<\/span><span class=\"p\">(<\/span><span class=\"s1\">'API v1'<\/span><span class=\"p\">,<\/span> <span class=\"ss\">limit: <\/span><span class=\"mi\">200<\/span><span class=\"p\">,<\/span> <span class=\"ss\">period: <\/span><span class=\"mi\">60<\/span><span class=\"p\">)<\/span> <span class=\"k\">do<\/span> <span class=\"o\">|<\/span><span class=\"n\">req<\/span><span class=\"o\">|<\/span>\n  <span class=\"k\">if<\/span> <span class=\"n\">req<\/span><span class=\"p\">.<\/span><span class=\"nf\">path<\/span> <span class=\"o\">=~<\/span> <span class=\"s1\">'\/api\/v1\/'<\/span>\n    <span class=\"n\">req<\/span><span class=\"p\">.<\/span><span class=\"nf\">env<\/span><span class=\"p\">[<\/span><span class=\"s1\">'rack.session'<\/span><span class=\"p\">][<\/span><span class=\"s1\">'session_id'<\/span><span class=\"p\">]<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"query-parsing\">Query parsing<\/h3>\n\n<p>Before a query is executed, it is first parsed. We once received a pen-test report evidencing that its possible to craft an invalid query string that OOM\u2019d the server. For example:<\/p>\n\n<div class=\"language-graphql highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">query<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"n\">__typename<\/span><span class=\"w\"> <\/span><span class=\"k\">@a<\/span><span class=\"w\"> <\/span><span class=\"k\">@b<\/span><span class=\"w\"> <\/span><span class=\"k\">@c<\/span><span class=\"w\"> <\/span><span class=\"k\">@d<\/span><span class=\"w\"> <\/span><span class=\"k\">@e<\/span><span class=\"w\"> <\/span><span class=\"p\">...<\/span><span class=\"w\"> <\/span><span class=\"c\"># imagine 1k+ more of these<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre><\/div><\/div>\n\n<p>This is a <strong>syntactically<\/strong> valid query, but invalid for our schema. A spec compliant server will parse this and start building an errors response containing thousands of errors which we found consumed <strong>2,000x<\/strong> more memory than the query string itself. Because of this memory amplification, its not enough to just limit the payload size, as you will have valid queries that are larger than the the smallest dangerous malicious query.<\/p>\n\n<p>If your server exposes a concept of maximum number of errors to accrue before abandoning parsing, <a href=\"https:\/\/github.com\/rmosolgo\/graphql-ruby\/issues\/4154\">this can be mitigated<\/a>. If not, you\u2019ll have to roll your own solution. There is no REST equivalent to this attack of this severity.<\/p>\n\n<h2 id=\"performance\">Performance<\/h2>\n\n<p>When it comes to performance in GraphQL people often talk about it\u2019s incompatibility with HTTP caching. For me personally, this has not been an issue. For SaaS applications, data is usually highly user specific and serving stale data is unacceptable, so I have not found myself missing response caches (or the cache invalidation bugs they cause\u2026).<\/p>\n\n<p>The major performance problems I <strong>did<\/strong> find myself dealing with were\u2026<\/p>\n\n<h3 id=\"data-fetching-and-the-n1-problem\">Data fetching and the N+1 problem<\/h3>\n\n<p>I think this issue is pretty widely understood nowadays. TLDR: if a field resolver hits an external data source such as a DB or HTTP API, and it is nested in a list containing N items, it will do those calls N times.<\/p>\n\n<p>This is not a unique problem to GraphQL, and actually the strict GraphQL resolution algorithm has allowed most libraries to share a common solution: <a href=\"https:\/\/graphql-ruby.org\/dataloader\/overview.html\">the Dataloader pattern<\/a>. Unique to GraphQL though is the fact that since it is a query language, this can <strong>become<\/strong> a problem with no backend changes when a client modifies a query. As a result, I found you end up having to defensively introduce the Dataloader abstraction everywhere <em>just in case<\/em> a client ends up fetching a field in a list context in the future. This is a lot of boilerplate to write and maintain.<\/p>\n\n<p>Meanwhile, in REST, we can generally hoist nested N+1 queries up to the controller, which I think is a pattern much easier to wrap your head around:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class<\/span> <span class=\"nc\">BlogsController<\/span> <span class=\"o\">&lt;<\/span> <span class=\"no\">ApplicationController<\/span>\n  <span class=\"k\">def<\/span> <span class=\"nf\">index<\/span>\n    <span class=\"vi\">@latest_blogs<\/span> <span class=\"o\">=<\/span> <span class=\"no\">Blog<\/span><span class=\"p\">.<\/span><span class=\"nf\">limit<\/span><span class=\"p\">(<\/span><span class=\"mi\">25<\/span><span class=\"p\">).<\/span><span class=\"nf\">includes<\/span><span class=\"p\">(<\/span><span class=\"ss\">:author<\/span><span class=\"p\">,<\/span> <span class=\"ss\">:tags<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">render<\/span> <span class=\"ss\">json: <\/span><span class=\"no\">BlogSerializer<\/span><span class=\"p\">.<\/span><span class=\"nf\">render<\/span><span class=\"p\">(<\/span><span class=\"vi\">@latest_blogs<\/span><span class=\"p\">)<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nf\">show<\/span>\n    <span class=\"c1\"># No prefetching necessary here since N=1<\/span>\n    <span class=\"vi\">@blog<\/span> <span class=\"o\">=<\/span> <span class=\"no\">Blog<\/span><span class=\"p\">.<\/span><span class=\"nf\">find<\/span><span class=\"p\">(<\/span><span class=\"n\">params<\/span><span class=\"p\">[<\/span><span class=\"ss\">:id<\/span><span class=\"p\">])<\/span>\n    <span class=\"n\">render<\/span> <span class=\"ss\">json: <\/span><span class=\"no\">BlogSerializer<\/span><span class=\"p\">.<\/span><span class=\"nf\">render<\/span><span class=\"p\">(<\/span><span class=\"vi\">@blog<\/span><span class=\"p\">)<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"authorisation-and-the-n1-problem\">Authorisation and the N+1 problem<\/h3>\n\n<p>But wait, there\u2019s more N+1s! If you followed the advice earlier of integrating with your library\u2019s authorisation framework, you\u2019ve now got a whole new category of N+1 problems to deal with. Lets continue with our X API example from earlier:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class<\/span> <span class=\"nc\">UserType<\/span> <span class=\"o\">&lt;<\/span> <span class=\"no\">GraphQL<\/span><span class=\"o\">::<\/span><span class=\"no\">BaseObject<\/span>\n  <span class=\"n\">field<\/span> <span class=\"ss\">:handle<\/span><span class=\"p\">,<\/span> <span class=\"no\">String<\/span>\n  <span class=\"n\">field<\/span> <span class=\"ss\">:birthday<\/span><span class=\"p\">,<\/span> <span class=\"ss\">authorize_with: :view_pii<\/span>\n<span class=\"k\">end<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">UserPolicy<\/span> <span class=\"o\">&lt;<\/span> <span class=\"no\">ApplicationPolicy<\/span>\n  <span class=\"k\">def<\/span> <span class=\"nf\">view_pii?<\/span>\n    <span class=\"c1\"># Oh no, I hit the DB to fetch the user's friends<\/span>\n    <span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"nf\">friends_with?<\/span><span class=\"p\">(<\/span><span class=\"n\">record<\/span><span class=\"p\">)<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<div class=\"language-graphql highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">query<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"n\">me<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"n\">friends<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"c\"># returns N Users<\/span><span class=\"w\">\n      <\/span><span class=\"n\">handle<\/span><span class=\"w\">\n      <\/span><span class=\"n\">birthday<\/span><span class=\"w\"> <\/span><span class=\"c\"># runs UserPolicy#view_pii? N times<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre><\/div><\/div>\n\n<p>This is actually trickier to deal with than our previous example, because authorisation code is not always run in a GraphQL context. It may for example be run in a background job or an HTML endpoint. That means we can\u2019t just reach for a Dataloader naively, because Dataloaders expect to be run from within GraphQL (in the Ruby implementation anyway).<\/p>\n\n<p>In my experience, this is actually <strong>the biggest source of performance issues<\/strong>. We would regularly find that our queries were spending more time authorising data than anything else. Again, this problem simply does not exist in the REST world.<\/p>\n\n<p>I have mitigated this using nasty things like <a href=\"https:\/\/api.rubyonrails.org\/classes\/ActiveSupport\/CurrentAttributes.html\">request level globals<\/a> to memoise data across policy calls, but its never felt great.<\/p>\n\n<h2 id=\"coupling\">Coupling<\/h2>\n\n<p>In my experience, in a mature GraphQL codebase, your business logic is forced into the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transport_layer\">transport layer<\/a>. This happens through a number of mechanisms, some of which we\u2019ve already talked about:<\/p>\n\n<ul>\n  <li>Solving data authorisation leads to peppering authorisation rules throughout your GraphQL types<\/li>\n  <li>Solving mutation \/ argument authorisation leads to peppering authorisation rules throughout your GraphQL arguments<\/li>\n  <li>Solving resolver data fetching N+1s leads to moving this logic into GraphQL specific dataloaders<\/li>\n  <li>Leveraging the (lovely) <a href=\"https:\/\/graphql-ruby.org\/pagination\/using_connections\">Relay Connection<\/a> pattern leads to moving data fetching logic into GraphQL specific <a href=\"https:\/\/graphql-ruby.org\/pagination\/custom_connections\">custom connection objects<\/a><\/li>\n<\/ul>\n\n<p>The net effect of all of this is to meaningfully test your application you <strong>must<\/strong> extensively test at the integration layer, i.e. by running GraphQL queries. I have found this makes for a painful experience. Any errors encountered are captured by the framework, leading to the fun task of reading stack traces in JSON GraphQL error responses. Since so much around authorisation and Dataloaders happens inside the framework, debugging is often much harder as the breakpoint you want is not in application code.<\/p>\n\n<p>And of course, again, since its a query language you\u2019re going to be writing a lot more tests to confirm that all those argument and field level behaviours we mentioned are working correctly.<\/p>\n\n<h2 id=\"complexity\">Complexity<\/h2>\n\n<p>Taken in aggregate, the various mitigations to security and performance issues we\u2019ve gone through add <strong>significant<\/strong> complexity to a codebase. It\u2019s not that REST does not have these problems (though it certainly has fewer), it\u2019s just that the REST solutions are generally much simpler for a backend developer to implement and understand.<\/p>\n\n<h2 id=\"and-more\">And more\u2026<\/h2>\n\n<p>So those are the major reasons I am, for the most part, over GraphQL. I have a few more peeves, but to keep this article growing further I\u2019ll summarise them here..<\/p>\n\n<ul>\n  <li>GraphQL discourages breaking changes and provides no tools to deal with them. This adds needless complexity for those who control all their clients, who will have to <a href=\"https:\/\/graphql-ruby.org\/changesets\/overview.html\">find workarounds<\/a>.<\/li>\n  <li>Reliance on HTTP response codes turns up everywhere in tooling, so dealing with the fact that 200 can mean everything from everything is Ok through to everything is down can be quite annoying.<\/li>\n  <li>Fetching all your data in one query in the HTTP 2+ age is often not beneficial to response time, in fact it will worsen it if your server is not parallelised, vs sending separate requests to separate servers to process in parallel.<\/li>\n<\/ul>\n\n<h2 id=\"alternatives\">Alternatives<\/h2>\n\n<p>Ok, end of the rant. What would I recommend instead? To be up front, I am definitely early in the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Gartner_hype_cycle\">hype cycle<\/a> here, but right now my view is that if you:<\/p>\n\n<ol>\n  <li>Control all your clients<\/li>\n  <li>Have \u22643 clients<\/li>\n  <li>Have a client written in a statically typed language<\/li>\n  <li>Are using &gt;1 language across the server and clients<sup id=\"fnref:2\" role=\"doc-noteref\"><a href=\"#fn:2\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup><\/li>\n<\/ol>\n\n<p>You are probably better off exposing an <strong>OpenAPI 3.0+<\/strong> compliant JSON REST API. If, as in my experience, the main thing your frontend devs like about GraphQL is its self documenting type safe nature, I think this will work well for you. Tooling in this area has improved a lot since GraphQL came on the scene; there are many options for generating typed client code even down to <a href=\"https:\/\/orval.dev\/overview\">framework specific data fetching libraries<\/a>. My experience so far is pretty close to \u201cthe best parts of what <strong>I<\/strong> used GraphQL for, without the complexity Facebook needed\u201d.<\/p>\n\n<p>As with GraphQL there\u2019s a couple of implementation approach\u2026<\/p>\n\n<p><strong>Implementation first<\/strong> tooling generates OpenAPI specs from a typed \/ type hinted server. <a href=\"https:\/\/fastapi.tiangolo.com\/\">FastAPI<\/a> in Python and <a href=\"https:\/\/github.com\/lukeautry\/tsoa\">tsoa<\/a> in TypeScript are good examples of this approach<sup id=\"fnref:3\" role=\"doc-noteref\"><a href=\"#fn:3\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup>. This is the approach I have the most experience with, and I think it works well.<\/p>\n\n<p><strong>Specification first<\/strong> is equivalent to \u201cschema first\u201d in GraphQL. Spec first tooling generates code from a hand written spec. I can\u2019t say I\u2019ve ever looked at an OpenAPI YAML file and thought \u201cI would love to have written that myself\u201d, but the recent release of <a href=\"https:\/\/typespec.io\/\">TypeSpec<\/a> changes things entirely. With it could come a quite elegant schema first workflow:<\/p>\n\n<ol>\n  <li>Write a succinct human readable TypeSpec schema<\/li>\n  <li>Generate an OpenAPI YAML spec from it<\/li>\n  <li>Generate statically typed API client for your frontend language of choice (e.g. <a href=\"https:\/\/orval.dev\/overview\">TypeScript<\/a>)<\/li>\n  <li>Generate statically typed server handlers for your backend language &amp; server framework (e.g. <a href=\"https:\/\/docs.buildwithfern.com\/server-boilerplate\/server-boilerplate\/express-js\">TypeScript + Express<\/a>, <a href=\"https:\/\/docs.buildwithfern.com\/server-boilerplate\/server-boilerplate\/fast-api\">Python + FastAPI<\/a>, <a href=\"https:\/\/github.com\/deepmap\/oapi-codegen\">Go + Echo<\/a>)<\/li>\n  <li>Write an implementation for that handler that compiles, safe in the knowledge that it will be type safe<\/li>\n<\/ol>\n\n<p>This approach is less mature but I think has a lot of promise.<\/p>\n\n<p>To me, it seems like powerful <strong>and<\/strong> simpler options are here, and I\u2019m excited to learn their drawbacks next \ud83d\ude04.<\/p>\n\n<p><em>Thanks for reading! See <a href=\"https:\/\/news.ycombinator.com\/item?id=40521518\">Hacker News<\/a> and <a href=\"https:\/\/www.reddit.com\/r\/programming\/comments\/1d48m1p\/why_after_6_years_im_over_graphql\/\">Reddit<\/a> for more discussion on this article.<\/em><\/p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\" role=\"doc-endnote\">\n      <p>Persisted queries are also a mitigation for this and many attacks, but if you actually want to expose a customer facing GraphQL API, persisted queries are not an option.\u00a0<a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:2\" role=\"doc-endnote\">\n      <p>Otherwise a language specific solution like <a href=\"https:\/\/trpc.io\/\">tRPC<\/a> might be a better fit.\u00a0<a href=\"#fnref:2\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:3\" role=\"doc-endnote\">\n      <p>In Ruby, I guess because type hints are not popular,  there is no equivalent approach. Instead we have <a href=\"https:\/\/github.com\/rswag\/rswag\">rswag<\/a> which generates OpenAPI specs from request specs. It would be cool if we could build an OpenAPI spec from Sorbet \/ RBS typed endpoints!\u00a0<a href=\"#fnref:3\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Fri, 24 May 2024 13:01:00 +0000","link":"https:\/\/bessey.dev\/blog\/2024\/05\/24\/why-im-over-graphql\/","guid":"https:\/\/bessey.dev\/blog\/2024\/05\/24\/why-im-over-graphql\/","category":["ruby","rails","graphql","rest","openapi"]},{"title":"Server Side Rendering for React + Apollo GraphQL Client","description":"<p>In a previous post I talked about how I set up <a href=\"\/blog\/2018\/08\/04\/rails-webpacker-react-ssr\/\">server side rendering of React components in Rails with Hypernova<\/a>. I went on to <a href=\"\/blog\/2018\/08\/05\/apollo-graphql-prefetching\/\">build a complex Ruby based GraphQL data pre-fetcher<\/a> because I could not work out how to do asynchronous pre-fetching of data in Hypernova alone. Well, it turns out though unclearly documented, its actually quite easy to do async pre-render work in Hypernova. That means we don\u2019t need to do the crazy things I was doing in my previous post, and can instead pull off my dream: <strong>server side rendered React, served by the back-end language \/ framework of your choosing.<\/strong><\/p>\n\n<p>I\u2019m going to assume you\u2019ve already <a href=\"\/blog\/2018\/08\/04\/rails-webpacker-react-ssr\/\">set up Hypernova with Rails<\/a> (or the back-end of your choosing). In this post, I will cover:<\/p>\n<ol>\n  <li>Understanding how Hypernova\u2019s renderer works<\/li>\n  <li>Extending it to support pre-fetching GraphQL data with Apollo Client<\/li>\n  <li>Extracting this GraphQL data for rehydration on the client\u2019s Apollo Client<\/li>\n  <li>Server side rendering your component with this pre-fetched data included<\/li>\n<\/ol>\n\n<!-- more -->\n\n<p>Throughout this I will use snippets of code from an example repo I put together, occasionally modified for brevity. If you prefer to see a complete example up front, see <a href=\"https:\/\/github.com\/bessey\/hypernova_apollo_rails\">my example repo on GitHub<\/a>.<\/p>\n\n<h3 id=\"1-understanding-the-hypernova-renderer\">1. Understanding the Hypernova Renderer<\/h3>\n\n<p>If you followed my previous post, you should have a file something like this where you register your React components with the Hypernova renderer.<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ app\/javascript\/packs\/react-hypernova.js<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">React<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">renderReact<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">hypernova-react<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"nx\">HelloWorldComponent<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">..\/components\/HelloWorld<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">HelloWorld<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">renderReact<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">HelloWorld<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"nx\">HelloWorldComponent<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>In order to customize <code class=\"language-plaintext highlighter-rouge\">renderReact<\/code> to our needs, we first need to understand it. We can dive into the <a href=\"https:\/\/github.com\/airbnb\/hypernova-react\/blob\/82b92bafcc090b8a046062590e310b8fef2be029\/src\/index.js\">hypernova-react source code<\/a> to learn  what exactly <code class=\"language-plaintext highlighter-rouge\">renderReact<\/code> does. Here\u2019s the source code for posterity:<\/p>\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ hypernova-react\/src\/index.js<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">renderReact<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"nx\">component<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">hypernova<\/span><span class=\"p\">({<\/span>\n  <span class=\"nx\">server<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"nx\">props<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">contents<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">ReactDOMServer<\/span><span class=\"p\">.<\/span><span class=\"nx\">renderToString<\/span><span class=\"p\">(<\/span><span class=\"nx\">React<\/span><span class=\"p\">.<\/span><span class=\"nx\">createElement<\/span><span class=\"p\">(<\/span><span class=\"nx\">component<\/span><span class=\"p\">,<\/span> <span class=\"nx\">props<\/span><span class=\"p\">));<\/span>\n      <span class=\"k\">return<\/span> <span class=\"nx\">serialize<\/span><span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"nx\">contents<\/span><span class=\"p\">,<\/span> <span class=\"nx\">props<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">};<\/span>\n  <span class=\"p\">},<\/span>\n\n  <span class=\"nx\">client<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">payloads<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">load<\/span><span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">payloads<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">payloads<\/span><span class=\"p\">.<\/span><span class=\"nx\">forEach<\/span><span class=\"p\">((<\/span><span class=\"nx\">payload<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">const<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">node<\/span><span class=\"p\">,<\/span> <span class=\"nx\">data<\/span> <span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">payload<\/span><span class=\"p\">;<\/span>\n        <span class=\"kd\">const<\/span> <span class=\"nx\">element<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">React<\/span><span class=\"p\">.<\/span><span class=\"nx\">createElement<\/span><span class=\"p\">(<\/span><span class=\"nx\">component<\/span><span class=\"p\">,<\/span> <span class=\"nx\">data<\/span><span class=\"p\">);<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">ReactDOM<\/span><span class=\"p\">.<\/span><span class=\"nx\">hydrate<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">ReactDOM<\/span><span class=\"p\">.<\/span><span class=\"nx\">hydrate<\/span><span class=\"p\">(<\/span><span class=\"nx\">element<\/span><span class=\"p\">,<\/span> <span class=\"nx\">node<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">ReactDOM<\/span><span class=\"p\">.<\/span><span class=\"nx\">render<\/span><span class=\"p\">(<\/span><span class=\"nx\">element<\/span><span class=\"p\">,<\/span> <span class=\"nx\">node<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nx\">component<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">},<\/span>\n<span class=\"p\">});<\/span>\n<\/code><\/pre><\/div><\/div>\n<p>So to summarize the above implementation, <code class=\"language-plaintext highlighter-rouge\">hypernova-react<\/code> is passing <code class=\"language-plaintext highlighter-rouge\">hypernova()<\/code> two functions. First, one for rendering a given <code class=\"language-plaintext highlighter-rouge\">component<\/code> on the <em>server<\/em>. Then, on the <em>client<\/em>, one for finding that rendered HTML in the DOM and rehydrating it as a live React component.<\/p>\n\n<p>But what is the <code class=\"language-plaintext highlighter-rouge\">hypernova()<\/code> call <em>doing<\/em> with these functions? If we go look <a href=\"https:\/\/github.com\/airbnb\/hypernova\/blob\/fdf6b8c06d8bcc9520a9e532735a3fce4c48c8c3\/src\/index.js#L85\">in <em>it\u2019s<\/em> source code<\/a> we can see the answer is not much at all!<\/p>\n\n<div class=\"language-js highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ hypernova\/src\/index.js<\/span>\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"kd\">function<\/span> <span class=\"nx\">hypernova<\/span><span class=\"p\">(<\/span><span class=\"nx\">runner<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return<\/span> <span class=\"k\">typeof<\/span> <span class=\"nb\">window<\/span> <span class=\"o\">===<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">undefined<\/span><span class=\"dl\">'<\/span>\n    <span class=\"p\">?<\/span> <span class=\"nx\">runner<\/span><span class=\"p\">.<\/span><span class=\"nx\">server<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">:<\/span> <span class=\"nx\">runner<\/span><span class=\"p\">.<\/span><span class=\"nx\">client<\/span><span class=\"p\">();<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>It turns out the Hypernova call itself is just a helper function to call the appropriate client \/ server function we passed in based on environment. No fancy business going on at all! This means we can now be confident in knowing the only place that needs to change is the <code class=\"language-plaintext highlighter-rouge\">server()<\/code> implementation passed into the <code class=\"language-plaintext highlighter-rouge\">renderReact<\/code> definition.<\/p>\n\n<h3 id=\"2-pre-fetching-apollo-graphql-data-on-the-server\">2. Pre-fetching Apollo GraphQL Data on the Server<\/h3>\n\n<p>We now know what needs changing, <code class=\"language-plaintext highlighter-rouge\">server()<\/code> needs to pre-fetch our data requirements before calling <code class=\"language-plaintext highlighter-rouge\">ReactDOMServer.renderToString<\/code>. But how can we achieve that? Well fortunately the excellent developers of Apollo have our backs. The <code class=\"language-plaintext highlighter-rouge\">react-apollo<\/code> library\u2019s <a href=\"https:\/\/www.apollographql.com\/docs\/react\/features\/server-side-rendering.html#getDataFromTree\">getDataFromTree<\/a> provides a simple way to build a Promise that will only resolve when all data has been loaded for a given React component tree. Its so unbelievably simple that in fact that it\u2019s practically magic, here\u2019s an example of its usage:<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">getDataFromTree<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-apollo<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"c1\">\/\/ 1. Build the JSX tree<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">App<\/span> <span class=\"o\">=<\/span> <span class=\"p\">&lt;<\/span><span class=\"nc\">MyComponentThatFetchesData<\/span><span class=\"p\">\/&gt;<\/span>\n<span class=\"c1\">\/\/ 2. Extract the data requirements for the given tree with Apollo<\/span>\n<span class=\"nx\">getDataFromTree<\/span><span class=\"p\">(<\/span><span class=\"nx\">App<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"c1\">\/\/ 3. Now render the tree, knowing that the data has been fetched!<\/span>\n  <span class=\"k\">return<\/span> <span class=\"nx\">ReactDOM<\/span><span class=\"p\">.<\/span><span class=\"nx\">renderToString<\/span><span class=\"p\">(<\/span><span class=\"nx\">App<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">})<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"3-passing-the-pre-fetched-graphql-data-for-rehydration-on-the-client\">3. Passing the Pre-fetched GraphQL Data For Rehydration on the Client<\/h3>\n\n<p>Unfortunately, it\u2019s not enough to render the component with its data loaded. Doing so will initially render your component as you desire, but the second React starts, the components will revert to its \u2018loading\u2019 state, because the browser\u2019s Apollo Client cache is empty! We\u2019ll also need to extract the contents of the server\u2019s Apollo Client cache, and serialize it in some way that the browser\u2019s can read.<\/p>\n\n<p>Extracting the cache for rehydration is fairly easy:<\/p>\n<div class=\"language-js highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">import<\/span> <span class=\"nx\">ApolloClient<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">apollo-boost<\/span><span class=\"dl\">\"<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">InMemoryCache<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">apollo-cache-inmemory<\/span><span class=\"dl\">\"<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">client<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">ApolloClient<\/span><span class=\"p\">()<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">data<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">extract<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre><\/div><\/div>\n<p>\u2026 as is hydrating a new client with that cache data:<\/p>\n<div class=\"language-js highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">cache<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">InMemoryCache<\/span><span class=\"p\">({}).<\/span><span class=\"nx\">restore<\/span><span class=\"p\">(<\/span><span class=\"nx\">data<\/span><span class=\"p\">)<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">newClient<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">ApolloClient<\/span><span class=\"p\">({<\/span><span class=\"na\">cache<\/span><span class=\"p\">:<\/span> <span class=\"nx\">cache<\/span><span class=\"p\">})<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>So you will have to ensure your components support passing in an Apollo Client instance through props (for the <em>server<\/em>), but fall back to creating a new instance on the <em>client<\/em>. When creating a new Apollo Client instance, it should hydrate from <code class=\"language-plaintext highlighter-rouge\">window.SOME_GLOBAL<\/code>. We\u2019ll get to how to get our cached data onto <code class=\"language-plaintext highlighter-rouge\">window.SOME_GLOBAL<\/code> shortly. To keep all this functionality composable we can use a Higher Order Component:<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ app\/javascript\/containers\/withApollo.js<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">React<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">ApolloProvider<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-apollo<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">ApolloClient<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">apollo-boost<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">InMemoryCache<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">apollo-cache-inmemory<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"nx\">ComposedComponent<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">WithApollo<\/span> <span class=\"kd\">extends<\/span> <span class=\"nx\">React<\/span><span class=\"p\">.<\/span><span class=\"nx\">Component<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span><span class=\"nx\">props<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">super<\/span><span class=\"p\">(<\/span><span class=\"nx\">props<\/span><span class=\"p\">);<\/span>\n      <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">apollo<\/span> <span class=\"o\">=<\/span>\n        <span class=\"nx\">props<\/span><span class=\"p\">.<\/span><span class=\"nx\">apolloClient<\/span> <span class=\"o\">||<\/span>\n          <span class=\"k\">new<\/span> <span class=\"nx\">ApolloClient<\/span><span class=\"p\">({<\/span>\n            <span class=\"na\">uri<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">https:\/\/api.graphcms.com\/simple\/v1\/swapi<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n            <span class=\"na\">cache<\/span><span class=\"p\">:<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">InMemoryCache<\/span><span class=\"p\">({}).<\/span><span class=\"nx\">restore<\/span><span class=\"p\">((<\/span><span class=\"nb\">window<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nb\">window<\/span><span class=\"p\">.<\/span><span class=\"nx\">__APOLLO_STATE__<\/span><span class=\"p\">)<\/span> <span class=\"o\">||<\/span> <span class=\"p\">{})<\/span>\n          <span class=\"p\">});<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"nx\">render<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">return<\/span> <span class=\"p\">(<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nc\">ApolloProvider<\/span> <span class=\"na\">client<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">apollo<\/span><span class=\"si\">}<\/span><span class=\"p\">&gt;<\/span>\n          <span class=\"p\">&lt;<\/span><span class=\"nc\">ComposedComponent<\/span> <span class=\"si\">{<\/span><span class=\"p\">...<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">props<\/span><span class=\"si\">}<\/span> <span class=\"p\">\/&gt;<\/span>\n        <span class=\"p\">&lt;\/<\/span><span class=\"nc\">ApolloProvider<\/span><span class=\"p\">&gt;<\/span>\n      <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">};<\/span>\n<span class=\"p\">};<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now, as for getting the cache into <code class=\"language-plaintext highlighter-rouge\">window.__APOLLO_STATE__<\/code>\u2026 My devious solution for this is rendering a script tag alongside the component, so we can load our Apollo Client data from JSON, onto <code class=\"language-plaintext highlighter-rouge\">window<\/code>, and then remove ourself <em>before<\/em> React rehydrates. That\u2019s important, because in the client\u2019s view that script tag should not be in the Component\u2019s DOM. Luckily enough thanks to the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Document\/currentScript\">document.currentScript<\/a> API, it is possible for a <code class=\"language-plaintext highlighter-rouge\">&lt;script\/&gt;<\/code> tag to remove itself from the DOM during execution. The final result is this:<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ app\/javascript\/hypernovaApolloRenderer.jsx<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Fragment<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">function<\/span> <span class=\"nx\">buildApolloClientCacheComponent<\/span><span class=\"p\">(<\/span><span class=\"nx\">Component<\/span><span class=\"p\">,<\/span> <span class=\"nx\">clientCache<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">ComponentWithCache<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">props<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span>\n    <span class=\"p\">&lt;<\/span><span class=\"nc\">Fragment<\/span><span class=\"p\">&gt;<\/span>\n      <span class=\"si\">{<\/span><span class=\"cm\">\/*\n        Store Apollo Client state, per\n        https:\/\/www.apollographql.com\/docs\/react\/features\/server-side-rendering.html#getDataFromTree\n        then delete ourself because React will warn it wasn't expecting a script tag.\n        Deletion doesn't work in IE, but the only harm done is generating that React warning.\n      *\/<\/span><span class=\"si\">}<\/span>\n      <span class=\"p\">&lt;<\/span><span class=\"nt\">script<\/span>\n        <span class=\"na\">dangerouslySetInnerHTML<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"p\">{<\/span>\n          <span class=\"na\">__html<\/span><span class=\"p\">:<\/span> <span class=\"s2\">`window.__APOLLO_STATE__=<\/span><span class=\"p\">${<\/span><span class=\"nx\">JSON<\/span><span class=\"p\">.<\/span><span class=\"nx\">stringify<\/span><span class=\"p\">(<\/span>\n            <span class=\"nx\">clientCache<\/span>\n          <span class=\"p\">).<\/span><span class=\"nx\">replace<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/&lt;\/g<\/span><span class=\"p\">,<\/span> <span class=\"dl\">\"<\/span><span class=\"se\">\\\\<\/span><span class=\"s2\">u003c<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)}<\/span><span class=\"s2\">;\n          document.currentScript &amp;&amp; document.currentScript.remove();\n          `<\/span>\n        <span class=\"p\">}<\/span><span class=\"si\">}<\/span>\n      <span class=\"p\">\/&gt;<\/span>\n      <span class=\"p\">&lt;<\/span><span class=\"nc\">Component<\/span> <span class=\"si\">{<\/span><span class=\"p\">...<\/span><span class=\"nx\">props<\/span><span class=\"si\">}<\/span> <span class=\"p\">\/&gt;<\/span>\n    <span class=\"p\">&lt;\/<\/span><span class=\"nc\">Fragment<\/span><span class=\"p\">&gt;<\/span>\n  <span class=\"p\">);<\/span>\n  <span class=\"k\">return<\/span> <span class=\"nx\">ComponentWithCache<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"4-server-side-rendering-the-component-with-pre-fetched-data\">4. Server Side Rendering the Component With Pre-fetched Data<\/h3>\n\n<p>So now all that\u2019s left to do is integrate all this into our <code class=\"language-plaintext highlighter-rouge\">server()<\/code> implementation, but how? Well, here\u2019s the crucial part I missed last time: What isn\u2019t mentioned in the documentation for <code class=\"language-plaintext highlighter-rouge\">hypernova-react<\/code> or anywhere that I can see in <code class=\"language-plaintext highlighter-rouge\">hypernova<\/code> is that <code class=\"language-plaintext highlighter-rouge\">server()<\/code> can <strong>return a Promise<\/strong>. The provided implementation is synchronous, but it does not have to be. Armed with this knowledge, the remaining changes are relatively small:<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ app\/javascript\/hypernovaApolloRenderer.jsx<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Fragment<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">ReactDOM<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-dom<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">ReactDOMServer<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-dom\/server<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">hypernova<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">serialize<\/span><span class=\"p\">,<\/span> <span class=\"nx\">load<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">hypernova<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">ApolloClient<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">apollo-boost<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">getDataFromTree<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-apollo<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">createApolloClient<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/createApolloClient<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">renderReactWithApollo<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Component<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">hypernova<\/span><span class=\"p\">({<\/span>\n  <span class=\"nx\">server<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ 1. We make the function async so we can await in it<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">async<\/span> <span class=\"nx\">props<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"c1\">\/\/ 2. With a client instance we have access to, fetch the data from the component<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">client<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">ApolloClient<\/span><span class=\"p\">({<\/span> <span class=\"na\">uri<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">https:\/\/api.graphcms.com\/simple\/v1\/swapi<\/span><span class=\"dl\">\"<\/span> <span class=\"p\">});<\/span>\n      <span class=\"k\">await<\/span> <span class=\"nx\">getDataFromTree<\/span><span class=\"p\">(&lt;<\/span><span class=\"nc\">Component<\/span> <span class=\"si\">{<\/span><span class=\"p\">...<\/span><span class=\"nx\">props<\/span><span class=\"si\">}<\/span> <span class=\"na\">apolloClient<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"nx\">client<\/span><span class=\"si\">}<\/span> <span class=\"p\">\/&gt;);<\/span>\n\n      <span class=\"c1\">\/\/ 3. With our previously built cache side-loader, build a new component with the cache included in JSON<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">ComponentWithCache<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">buildApolloClientCacheComponent<\/span><span class=\"p\">(<\/span>\n        <span class=\"nx\">Component<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">extract<\/span><span class=\"p\">()<\/span>\n      <span class=\"p\">);<\/span>\n      <span class=\"c1\">\/\/ 4. Render with our prehydrated client, so we don't SSR a Loading screen<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">element<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">React<\/span><span class=\"p\">.<\/span><span class=\"nx\">createElement<\/span><span class=\"p\">(<\/span><span class=\"nx\">ComponentWithCache<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span>\n        <span class=\"p\">...<\/span><span class=\"nx\">props<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">apolloClient<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span>\n      <span class=\"p\">});<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">html<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">ReactDOMServer<\/span><span class=\"p\">.<\/span><span class=\"nx\">renderToString<\/span><span class=\"p\">(<\/span><span class=\"nx\">element<\/span><span class=\"p\">);<\/span>\n      <span class=\"k\">return<\/span> <span class=\"nx\">serialize<\/span><span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"nx\">html<\/span><span class=\"p\">,<\/span> <span class=\"nx\">props<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">};<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"c1\">\/\/ client() is unchanged<\/span>\n  <span class=\"c1\">\/\/ ...<\/span>\n<span class=\"p\">});<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>And with that, you\u2019re done, you have everything you need to server side render React components with Apollo data pre-fetched, or so I hope. If you\u2019ve gotten lost anywhere in this guide, or just want to see the whole lot put together, check out this <a href=\"https:\/\/github.com\/bessey\/hypernova_apollo_rails\">complete example repo on my GitHub<\/a>.<\/p>\n","pubDate":"Wed, 02 Jan 2019 13:01:00 +0000","link":"https:\/\/bessey.dev\/blog\/2019\/01\/02\/apollo-graphql-hypernova\/","guid":"https:\/\/bessey.dev\/blog\/2019\/01\/02\/apollo-graphql-hypernova\/","category":["ruby","rails","react","apollo","graphql"]},{"title":"Pre-fetching Data for Apollo GraphQL Client","description":"<p><strong>UPDATE: This post has been made redundant by my discovery of a simpler approach. Please see: <a href=\"\/blog\/2019\/01\/02\/apollo-graphql-hypernova\/\">Server Side Rendering for React + Apollo GraphQL Client<\/a>.<\/strong><\/p>\n\n<p>In a previous post I talked about how I set up <a href=\"\/blog\/2018\/08\/04\/rails-webpacker-react-ssr\/\">server side rendering of React components in Rails with Hypernova<\/a>. One detail I skimmed over in that post was <em>how<\/em> I got the data dependencies of our React components in Ruby-land. We\u2019re a React + GraphQL shop (via <a href=\"https:\/\/github.com\/apollographql\/apollo-client\">Apollo Client<\/a>), and following GraphQL best practices, our data requirements are <a href=\"https:\/\/www.apollographql.com\/docs\/react\/advanced\/fragments.html#colocating-fragments\">colocated with the components that need the data<\/a>, so this is a pretty tough problem. At first this seemed unsolvable, but thanks to some amazing tooling from the Apollo team, it can be done with surprising ease, and best of all no code duplication.<\/p>\n\n<p>In this post I will walk you through how to extract your React components\u2019 GraphQL queries, fragments and all, into a format a Rails app can read, run, enabling full data hydration and server side rendering. While I am using Rails and React, <strong>the principles of this tutorial can be applied to any server language with a GraphQL client, and to any JS framework using Apollo Client<\/strong> or (I believe) any GraphQL JS client that supports denoting queries with the <code class=\"language-plaintext highlighter-rouge\">gql<\/code> tag.<\/p>\n\n<!-- more -->\n\n<p>The fantastic tool we\u2019ll be using to accomplish this is <a href=\"https:\/\/github.com\/apollographql\/apollo-cli\">apollo-cli<\/a>, a multipurpose tool for GraphQL code generation and schema analysis. This tool is nuts, allowing you to do all sorts of interesting stuff, but what we\u2019re interested in is its ability to extract queries from a inline <code class=\"language-plaintext highlighter-rouge\">gql<\/code> tags in a React component and <code class=\"language-plaintext highlighter-rouge\">.graphql<\/code> files, into a JSON file easily read by another service.<\/p>\n\n<h3 id=\"extracting-your-client-queries\">Extracting Your Client Queries<\/h3>\n\n<p>To get started, lets install the CLI:<\/p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>yarn add dev apollo-cli\n<\/code><\/pre><\/div><\/div>\n\n<p>Now we need to save the GraphQL schema that Apollo is querying, as the the CLI\u2019s code-gen functionality relies on it. This is achieved with GraphQL\u2019s <a href=\"https:\/\/graphql.org\/learn\/introspection\/\">powerful introspection tooling<\/a>. You may well already be doing this some other way, as it is a common requirement of lots of interesting GraphQL tools. However, you don\u2019t need to; Apollo CLI provides this functionality with a one liner!<\/p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>yarn run apollo schema:download <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--endpoint<\/span> http:\/\/localhost:3000\/your\/api\/endpoint <span class=\"se\">\\<\/span>\n  config\/graphql_schema.json\n<\/code><\/pre><\/div><\/div>\n\n<p>Next up, the actually query extraction. What would otherwise be a mammoth task is once again an Apollo CLI one liner!<\/p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>yarn run apollo codegen:generate <span class=\"nt\">--schema<\/span><span class=\"o\">=<\/span>config\/graphql_schema.json <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--addTypename<\/span> <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--queries<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"app\/javascript\/**\/*.{js,jsx,graphql}\"<\/span> <span class=\"se\">\\<\/span>\n  config\/graphql_queries.json\n<\/code><\/pre><\/div><\/div>\n\n<p>Now go open <code class=\"language-plaintext highlighter-rouge\">config\/graphql_queries.json<\/code> and you should find every query and every fragment in your codebase extracted. There\u2019s a lot of stuff here, most of which we don\u2019t need for our purposes, so we\u2019re going to be focussing on just these parts:<\/p>\n\n<div class=\"language-js highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"p\">{<\/span>\n  <span class=\"c1\">\/\/ 'operations' contains all the queries found<\/span>\n  <span class=\"dl\">\"<\/span><span class=\"s2\">operations<\/span><span class=\"dl\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n    <span class=\"p\">{<\/span>\n      <span class=\"c1\">\/\/ the operation name of each query is extracted, this makes lookup much easier for us<\/span>\n      <span class=\"dl\">\"<\/span><span class=\"s2\">operationName<\/span><span class=\"dl\">\"<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">HelloWorld<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n      <span class=\"c1\">\/\/ and a version of the query with fragments inlined is also provided so we don't need to<\/span>\n      <span class=\"c1\">\/\/ stitch that together ourselves<\/span>\n      <span class=\"dl\">\"<\/span><span class=\"s2\">sourceWithFragments<\/span><span class=\"dl\">\"<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">query HelloWorld($id: ID!) {<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">  helloWorld(id: $id) {<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">    id<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">    name<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">  }<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">}<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">]<\/span>\n  <span class=\"c1\">\/\/ ...<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Thats all we need to run our query on any GraphQL client imaginable. For the rest of this tutorial I\u2019ll be using the Ruby <a href=\"https:\/\/github.com\/github\/graphql-client\">graphql-client<\/a> from Github in a Rails app, but the principles could be applied elsewhere too.<\/p>\n\n<p>By the way, since query extraction is completely dependent on the contents of your codebase, I recommend adding this file to your <code class=\"language-plaintext highlighter-rouge\">.gitignore<\/code> and generating it automatically at application build or deploy time. There\u2019s no sense risking this file getting stale, or having it show up in your pull request diffs for no good reason.<\/p>\n\n<h3 id=\"running-client-queries-on-the-server\">Running Client Queries on the Server<\/h3>\n\n<p>I\u2019ll start by setting up <code class=\"language-plaintext highlighter-rouge\">graphql-ruby<\/code> on my server, if you already have a functional client, you can skip this part.<\/p>\n\n<p>First add the client to your server:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>gem 'graphql-client', '~&gt; 0.13'\n<\/code><\/pre><\/div><\/div>\n\n<p>Now lets create a basic GraphQL Client configured for the endpoint. Its up to you where you put this code, we use <code class=\"language-plaintext highlighter-rouge\">lib\/<\/code> and require it in a Rails initializer, but do whatever works for you. Here\u2019s a minimal version of our client config:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">require<\/span> <span class=\"s2\">\"graphql\/client\"<\/span>\n<span class=\"nb\">require<\/span> <span class=\"s2\">\"graphql\/client\/http\"<\/span>\n\n<span class=\"k\">module<\/span> <span class=\"nn\">MyAPI<\/span>\n  <span class=\"c1\"># graphql-client has tooling to save and read your schema itself, but since we have already<\/span>\n  <span class=\"c1\"># saved one with Apollo CLI, lets transform that to a format that graphql-client can read<\/span>\n  <span class=\"n\">apollo_cli_output<\/span> <span class=\"o\">=<\/span> <span class=\"no\">File<\/span><span class=\"p\">.<\/span><span class=\"nf\">read<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"config\/graphql_schema.json\"<\/span><span class=\"p\">)<\/span>\n  <span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"s2\">\"data\"<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span> <span class=\"s2\">\"__schema\"<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"no\">JSON<\/span><span class=\"p\">.<\/span><span class=\"nf\">parse<\/span><span class=\"p\">(<\/span><span class=\"n\">apollo_cli_output<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span> <span class=\"p\">}<\/span>\n  <span class=\"no\">Schema<\/span> <span class=\"o\">=<\/span> <span class=\"no\">GraphQL<\/span><span class=\"o\">::<\/span><span class=\"no\">Client<\/span><span class=\"p\">.<\/span><span class=\"nf\">load_schema<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n  <span class=\"no\">HTTP<\/span> <span class=\"o\">=<\/span> <span class=\"no\">GraphQL<\/span><span class=\"o\">::<\/span><span class=\"no\">Client<\/span><span class=\"o\">::<\/span><span class=\"no\">HTTP<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"https:\/\/example.com\/graphql\"<\/span><span class=\"p\">)<\/span> <span class=\"k\">do<\/span>\n    <span class=\"c1\"># Customize adapter to your needs, for more info see:<\/span>\n    <span class=\"c1\"># https:\/\/github.com\/github\/graphql-client#configuration<\/span>\n  <span class=\"k\">end<\/span>\n  <span class=\"no\">Client<\/span> <span class=\"o\">=<\/span> <span class=\"no\">GraphQL<\/span><span class=\"o\">::<\/span><span class=\"no\">Client<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"ss\">schema: <\/span><span class=\"no\">Schema<\/span><span class=\"p\">,<\/span> <span class=\"ss\">execute: <\/span><span class=\"no\">HTTP<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now we\u2019re going to want some convenience methods to make getting a GraphQL query from our persisted queries file simple. <em>Here\u2019s one I made earlier<\/em>:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">module<\/span> <span class=\"nn\">MyAPI<\/span>\n  <span class=\"k\">class<\/span> <span class=\"nc\">PersistedQueryLookup<\/span>\n    <span class=\"no\">QUERIES_PATH<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">\"config\/graphql_queries.json\"<\/span>\n\n    <span class=\"nb\">attr_reader<\/span> <span class=\"ss\">:persisted_queries_data<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">initialize<\/span>\n      <span class=\"vi\">@persisted_queries_data<\/span> <span class=\"o\">=<\/span> <span class=\"n\">load_persisted_queries_data<\/span>\n    <span class=\"k\">end<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">for_operation<\/span><span class=\"p\">(<\/span><span class=\"nb\">name<\/span><span class=\"p\">)<\/span>\n      <span class=\"n\">operation<\/span> <span class=\"o\">=<\/span> <span class=\"n\">persisted_queries_data<\/span><span class=\"p\">[<\/span><span class=\"s2\">\"operations\"<\/span><span class=\"p\">].<\/span><span class=\"nf\">find<\/span> <span class=\"p\">{<\/span> <span class=\"o\">|<\/span><span class=\"n\">op<\/span><span class=\"o\">|<\/span> <span class=\"n\">op<\/span><span class=\"p\">[<\/span><span class=\"s2\">\"operationName\"<\/span><span class=\"p\">]<\/span> <span class=\"o\">==<\/span> <span class=\"nb\">name<\/span> <span class=\"p\">}<\/span>\n      <span class=\"k\">unless<\/span> <span class=\"n\">operation<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"no\">RuntimeError<\/span><span class=\"p\">,<\/span> <span class=\"s2\">\"Could not find persisted query called '<\/span><span class=\"si\">#{<\/span><span class=\"nb\">name<\/span><span class=\"si\">}<\/span><span class=\"s2\">', ensure you ran the Apollo query extractor recently\"<\/span>\n      <span class=\"k\">end<\/span>\n      <span class=\"n\">query_with_operation_name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">operation<\/span><span class=\"p\">[<\/span><span class=\"s2\">\"sourceWithFragments\"<\/span><span class=\"p\">]<\/span>\n      <span class=\"n\">query_with_operation_name<\/span><span class=\"p\">.<\/span><span class=\"nf\">gsub<\/span><span class=\"p\">(<\/span><span class=\"nb\">name<\/span><span class=\"p\">,<\/span> <span class=\"s2\">\"\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">end<\/span>\n\n    <span class=\"kp\">private<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">load_persisted_queries_data<\/span>\n      <span class=\"k\">unless<\/span> <span class=\"no\">File<\/span><span class=\"p\">.<\/span><span class=\"nf\">exist?<\/span><span class=\"p\">(<\/span><span class=\"no\">QUERIES_PATH<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"no\">RuntimeError<\/span><span class=\"p\">,<\/span> <span class=\"s2\">\"Cannot find <\/span><span class=\"si\">#{<\/span><span class=\"no\">QUERIES_PATH<\/span><span class=\"si\">}<\/span><span class=\"s2\">, ensure you ran the Apollo query extractor\"<\/span>\n      <span class=\"k\">end<\/span>\n      <span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"no\">File<\/span><span class=\"p\">.<\/span><span class=\"nf\">read<\/span><span class=\"p\">(<\/span><span class=\"no\">QUERIES_PATH<\/span><span class=\"p\">)<\/span>\n      <span class=\"no\">JSON<\/span><span class=\"p\">.<\/span><span class=\"nf\">parse<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">end<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now lets add a class method to our <code class=\"language-plaintext highlighter-rouge\">MyAPI<\/code> module to cache a singleton of this persisted query lookup class:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">module<\/span> <span class=\"nn\">MyAPI<\/span>\n  <span class=\"c1\"># Append this to the bottom of your MyAPI module...<\/span>\n\n  <span class=\"c1\"># Find a query extracted from the app\/javascript build by its operation name<\/span>\n  <span class=\"k\">def<\/span> <span class=\"nc\">self<\/span><span class=\"o\">.<\/span><span class=\"nf\">persisted_query<\/span><span class=\"p\">(<\/span><span class=\"n\">operation_name<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">persisted_queries<\/span><span class=\"p\">.<\/span><span class=\"nf\">for_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">operation_name<\/span><span class=\"p\">)<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nc\">self<\/span><span class=\"o\">.<\/span><span class=\"nf\">persisted_queries<\/span>\n    <span class=\"vi\">@lookup<\/span> <span class=\"o\">||=<\/span> <span class=\"no\">PersistedQueryLookup<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Great, now we can easily run a client query from a Rails controller! Since we might be parsing more than one query to our client, we\u2019re going to pass into the view a map of operation names to their respective results. This will come in handy when we make a general purpose Apollo cache hydrater.<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># app\/controllers\/my_controller.rb<\/span>\n<span class=\"k\">class<\/span> <span class=\"nc\">WorldsController<\/span> <span class=\"o\">&lt;<\/span> <span class=\"no\">ApplicationController<\/span>\n  <span class=\"c1\"># Parse query extracted from the React \/ Apollo app, to be used for hydration and server side rendering<\/span>\n  <span class=\"no\">OperationName<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">\"HelloWorld\"<\/span>\n  <span class=\"no\">Query<\/span> <span class=\"o\">=<\/span> <span class=\"no\">MyAPI<\/span><span class=\"o\">::<\/span><span class=\"no\">Client<\/span><span class=\"p\">.<\/span><span class=\"nf\">parse<\/span><span class=\"p\">(<\/span><span class=\"no\">MyAPI<\/span><span class=\"p\">.<\/span><span class=\"nf\">persisted_query<\/span><span class=\"p\">(<\/span><span class=\"no\">OperationName<\/span><span class=\"p\">))<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nf\">index<\/span>\n    <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"no\">MyAPI<\/span><span class=\"o\">::<\/span><span class=\"no\">Client<\/span><span class=\"p\">.<\/span><span class=\"nf\">query<\/span><span class=\"p\">(<\/span><span class=\"no\">Query<\/span><span class=\"p\">,<\/span> <span class=\"ss\">variables: <\/span><span class=\"p\">{<\/span><span class=\"ss\">id: <\/span><span class=\"n\">params<\/span><span class=\"p\">[<\/span><span class=\"ss\">:id<\/span><span class=\"p\">]})<\/span>\n    <span class=\"vi\">@data<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"no\">OperationName<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"n\">result<\/span><span class=\"p\">.<\/span><span class=\"nf\">data<\/span> <span class=\"p\">}<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"hydrating-the-apollo-client-with-prefetched-data\">Hydrating the Apollo Client with Prefetched Data<\/h3>\n\n<p>Ok, we\u2019ve got the query, we\u2019ve run it on the server, now we need to parse it into the view, and teach apollo how to write it into its internal normalized cache.<\/p>\n\n<p>In our view, lets parse those results as JSON through to our React component. Here I am using Hypernova, to learn more about that see <a href=\"\/blog\/2018\/08\/04\/rails-webpacker-react-ssr\/\">my previous post on SSR React in Rails<\/a>), but you could just as easily be parsing the prop in via a <code class=\"language-plaintext highlighter-rouge\">window.queryResults<\/code> global variable, or another mechanism. The important thing is: when your component mounts, it needs to have this data available to it.<\/p>\n\n<div class=\"language-erb highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">&lt;%<\/span> <span class=\"c1\"># app\/views\/worlds\/index.html.erb <\/span><span class=\"cp\">%&gt;<\/span>\n\n<span class=\"cp\">&lt;%=<\/span>\n  <span class=\"n\">render_react_component<\/span><span class=\"p\">(<\/span><span class=\"s1\">'HelloWorld'<\/span><span class=\"p\">,<\/span> <span class=\"ss\">queryResults: <\/span><span class=\"vi\">@data<\/span><span class=\"p\">.<\/span><span class=\"nf\">to_json<\/span><span class=\"p\">)<\/span>\n<span class=\"cp\">%&gt;<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Next, we\u2019ll make a general purpose Higher Order Component that we can wrap our HelloWorld component in, that will write these <code class=\"language-plaintext highlighter-rouge\">queryResults<\/code> to the Apollo internal cache. It would be nice if this functionality was built into Apollo, but it\u2019s not too hard to build ourselves using <a href=\"https:\/\/www.apollographql.com\/docs\/react\/advanced\/caching.html#writequery-and-writefragment\">Apollo\u2019s writeQuery API<\/a>:<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ app\/javascript\/containers\/withPreloadedQueries.jsx<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Component<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">React<\/span><span class=\"dl\">\"<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">withApollo<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-apollo<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"c1\">\/\/ You'll need to build your map of operation names to gql queries here:<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">query<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">components\/HelloWorld<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">queryMap<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"na\">HelloWorld<\/span><span class=\"p\">:<\/span> <span class=\"nx\">query<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ Wrap a component with a HOC that will takes a \"queryResults\" prop of the format:<\/span>\n<span class=\"c1\">\/\/  { \"MyOperationName\" =&gt; (JSON data for that operation) }<\/span>\n<span class=\"c1\">\/\/ ...and populates the Apollo cache with that preloaded data.<\/span>\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"kd\">function<\/span> <span class=\"nx\">withPreloadedQueries<\/span><span class=\"p\">(<\/span><span class=\"nx\">Component<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">class<\/span> <span class=\"nx\">WithPreloadedQueries<\/span> <span class=\"kd\">extends<\/span> <span class=\"nx\">Component<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">componentWillMount<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">props<\/span><span class=\"p\">.<\/span><span class=\"nx\">queryResults<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">queryResults<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">JSON<\/span><span class=\"p\">.<\/span><span class=\"nx\">parse<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">props<\/span><span class=\"p\">.<\/span><span class=\"nx\">queryResults<\/span><span class=\"p\">)<\/span>\n      <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"kd\">let<\/span> <span class=\"nx\">operationName<\/span> <span class=\"k\">in<\/span> <span class=\"nx\">queryResults<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"c1\">\/\/ Find the matching query to this operation name<\/span>\n        <span class=\"kd\">const<\/span> <span class=\"nx\">query<\/span> <span class=\"o\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">_lookupQuery<\/span><span class=\"p\">(<\/span><span class=\"nx\">operationName<\/span><span class=\"p\">)<\/span>\n        <span class=\"c1\">\/\/ Write the results to the Apollo Cache<\/span>\n        <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">props<\/span><span class=\"p\">.<\/span><span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">writeQuery<\/span><span class=\"p\">({<\/span> <span class=\"nx\">query<\/span><span class=\"p\">,<\/span> <span class=\"p\">...<\/span><span class=\"nx\">queryResults<\/span><span class=\"p\">[<\/span><span class=\"nx\">operationName<\/span><span class=\"p\">]<\/span> <span class=\"p\">})<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"nx\">render<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"p\">{<\/span><span class=\"nx\">queryResults<\/span><span class=\"p\">,<\/span> <span class=\"p\">...<\/span><span class=\"nx\">rest<\/span><span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">props<\/span>\n      <span class=\"k\">return<\/span> <span class=\"p\">&lt;<\/span><span class=\"nc\">Component<\/span> <span class=\"si\">{<\/span><span class=\"p\">...<\/span><span class=\"nx\">rest<\/span><span class=\"si\">}<\/span> <span class=\"p\">\/&gt;<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"nx\">_lookupQuery<\/span><span class=\"p\">(<\/span><span class=\"nx\">operationName<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">query<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">queryMap<\/span><span class=\"p\">[<\/span><span class=\"nx\">operationName<\/span><span class=\"p\">]<\/span>\n      <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"nx\">query<\/span><span class=\"p\">)<\/span> <span class=\"k\">throw<\/span> <span class=\"k\">new<\/span> <span class=\"nb\">Error<\/span><span class=\"p\">(<\/span><span class=\"s2\">`Missing Query <\/span><span class=\"p\">${<\/span><span class=\"nx\">operationName<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"p\">)<\/span>\n      <span class=\"k\">return<\/span> <span class=\"nx\">query<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">}<\/span>\n  <span class=\"k\">return<\/span> <span class=\"nx\">withApollo<\/span><span class=\"p\">(<\/span><span class=\"nx\">WithPreloadedQueries<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre><\/div><\/div>\n\n<p>And finally, we need to actually use that HOC by wrapping our HelloWorld component:<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ app\/javascript\/components\/HelloWorld.jsx<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"nx\">withPreloadedQueries<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">containers\/withPreloadedQueries<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"c1\">\/\/ You know... except your component is useful<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">HelloWorld<\/span> <span class=\"o\">=<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return<\/span> <span class=\"p\">&lt;<\/span><span class=\"nc\">Stuff<\/span><span class=\"p\">\/&gt;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"nx\">withPreloadedQueries<\/span><span class=\"p\">(<\/span><span class=\"nx\">HelloWorld<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>And we\u2019re done! The HOC has the side effect of synchronously writing the pre-fetched data into the Apollo store. The result is no different from the Apollo client running the query itself. Since its synchronous, your UI should <em>immediately<\/em> render into its finished state. No loading spinners, no placeholders, just a perfect initial render.<\/p>\n\n<p>This technique alone allows for really snappy renders of even the most complicated GraphQL component trees, with or without server side rendering. If you aren\u2019t worried about SEO, and have repeat visitors that can be expected to have your React code cached, this approach is all you need to have React components render instantly.<\/p>\n\n<p>Thanks for reading, and a big thanks to the Apollo team for making some of the best frontend software I\u2019ve ever used.<\/p>\n\n<p>Matt<\/p>\n","pubDate":"Sun, 05 Aug 2018 13:01:00 +0000","link":"https:\/\/bessey.dev\/blog\/2018\/08\/05\/apollo-graphql-prefetching\/","guid":"https:\/\/bessey.dev\/blog\/2018\/08\/05\/apollo-graphql-prefetching\/","category":["ruby","rails","react","apollo client","graphql"]},{"title":"Rails + React Server Side Rendering, with Webpacker + Hypernova","description":"<p>I recently discovered <a href=\"https:\/\/github.com\/airbnb\/hypernova-ruby\">Hypernova<\/a>, a wonderful tool from Airbnb, making the unimaginable possible: server side rendered React components, in a Rails app, with <em>no Node server required in development, or even production<\/em>.<\/p>\n\n<p>In the post, I\u2019ll walk you through how to make this a reality in four steps:<\/p>\n\n<ol>\n  <li>Installing <a href=\"https:\/\/github.com\/rails\/webpacker\">Webpacker<\/a> 3.4.1, in a Rails 4.2+ app<\/li>\n  <li>Installing <a href=\"https:\/\/github.com\/airbnb\/hypernova-ruby\">Hypernova Ruby Client<\/a>, initially just <em>client side<\/em> rendering React components<\/li>\n  <li>Configuring Webpacker + <a href=\"https:\/\/github.com\/airbnb\/hypernova\">Hypernova <em>Server<\/em><\/a>, to support rendering those same components <em>server side<\/em><\/li>\n  <li>Adding health checks, so we know things are working in production<\/li>\n<\/ol>\n\n<p>But first, let me explain what I mean by \u201cno Node server required\u201d\u2026 After all, if you want to do server side rendering, you need to run a Node process on your server, so how can you not have a dependency on Node? Well, the architecture of <a href=\"https:\/\/github.com\/airbnb\/hypernova-ruby\">Hypernova<\/a> is such that during render, if a connection cannot be quickly established with the Node process, or the process errors during render, it falls back to the usual client side rendering approach. Coming from a Rails shop that over the years has dipped its toes further and further into JS heavy frontend, this is a great comfort to me. I am not a Node guy, I don\u2019t have anything against Node, but I definitely don\u2019t have expertise in it. So if I can have the benefits of SSR, without adding points of failure, and without massive increase in app complexity, thats a dream come true! Its also great for development; as another engineer, you can come into this project, edit a SSR React component, and check it in your browser, all just from a <code class=\"language-plaintext highlighter-rouge\">rails server<\/code> command.<\/p>\n\n<!-- more -->\n\n<p>I should note, Hypernova has one pretty important constraint: it is synchronous. What this means in practice is <strong>you must pre-fetch critical data in Ruby land<\/strong>. If you don\u2019t do this, at best you\u2019ll be server side rendering a loading screen. This is a best practice anyway, since it means even <em>without<\/em> SSR your component is hydrated with data, and can immediately render meaningful content without loading screens etc. How to achieve this is outside the scope of this post, but <a href=\"\/blog\/2018\/08\/05\/apollo-graphql-prefetching\/\">for those using GraphQL for data fetching in their React code, check out this post<\/a>.<\/p>\n\n<p><small>\n<em>This post is adapted from <a href=\"https:\/\/qiita.com\/KeitaMoromizato\/items\/ea9cf6e787d851ed61e6\">another splendid one<\/a> by <a href=\"https:\/\/qiita.com\/KeitaMoromizato\">Keita Moromizato<\/a>, updated with the (current) latest version of Webpacker, and some deviations for my needs. Thanks Keita! We\u2019ve never met, and I don\u2019t speak Japanese, but I\u2019m standing on your shoulders here<\/em> \ud83d\ude04\n<\/small><\/p>\n\n<h3 id=\"step-1-webpacker\">Step 1: Webpacker<\/h3>\n\n<p>This part is pretty easy, we\u2019re just going to follow the installation instructions provided by <a href=\"https:\/\/github.com\/rails\/webpacker\/tree\/3-x-stable#installation\">Webpacker themselves<\/a>:<\/p>\n\n<p>Add to your Rails Gemfile:<\/p>\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">gem<\/span> <span class=\"s1\">'webpacker'<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'~&gt; 3.5'<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now run:<\/p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bundle\nbundle <span class=\"nb\">exec <\/span>rails webpacker:install webpacker:install:react\n<\/code><\/pre><\/div><\/div>\n\n<p>We\u2019re going to make a pack whos exports will be the React component(s) we intend to Server Side Render. This is because in step 3 we will find we need to build that pack twice, once for the client, and once for the server.<\/p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"nb\">touch <\/span>app\/javascript\/packs\/react-hypernova.js\n<\/code><\/pre><\/div><\/div>\n\n<p>And finally, ensure the layout you intend to render React components into requires your generated application pack:<\/p>\n<div class=\"language-erb highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">&lt;%=<\/span> <span class=\"n\">javascript_pack_tag<\/span> <span class=\"s1\">'react-hypernova'<\/span> <span class=\"cp\">%&gt;<\/span>\n<span class=\"cp\">&lt;%=<\/span> <span class=\"n\">stylesheet_pack_tag<\/span> <span class=\"s1\">'react-hypernova'<\/span> <span class=\"cp\">%&gt;<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now, we\u2019re ready to render components. Webpacker hooks into the asset pipeline, compiling your packs on refresh without any extra config. Its <em>possible<\/em> to run the dev server via <code class=\"language-plaintext highlighter-rouge\">bin\/webpack-dev-server<\/code>, which has the benefit of supporting React Hot Module Reloading, but that too is for another post.<\/p>\n\n<h3 id=\"step-2-hypernova-client\">Step 2: Hypernova Client<\/h3>\n\n<p>Again, we\u2019re following the <a href=\"https:\/\/github.com\/airbnb\/hypernova-ruby#getting-started\">getting started instructions<\/a>, starting with a gem addition:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">gem<\/span> <span class=\"s1\">'hypernova'<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now to configure the initializer. This doesn\u2019t matter much yet, as we aren\u2019t starting the Hypernova <em>server<\/em> till step 3:<\/p>\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># config\/initializers\/hypernova.rb<\/span>\n<span class=\"no\">Hypernova<\/span><span class=\"p\">.<\/span><span class=\"nf\">configure<\/span> <span class=\"k\">do<\/span> <span class=\"o\">|<\/span><span class=\"n\">config<\/span><span class=\"o\">|<\/span>\n  <span class=\"n\">config<\/span><span class=\"p\">.<\/span><span class=\"nf\">host<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">\"localhost\"<\/span>\n  <span class=\"n\">config<\/span><span class=\"p\">.<\/span><span class=\"nf\">port<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">\"3030\"<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Next, we need to instrument any controller that will be rendering Hypernova components:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">class<\/span> <span class=\"nc\">MyController<\/span> <span class=\"o\">&lt;<\/span> <span class=\"no\">ApplicationController<\/span>\n  <span class=\"n\">around_action<\/span> <span class=\"ss\">:hypernova_render_support<\/span>\n<span class=\"k\">end<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Oh, and I guess I\u2019ll need a contrived component for rendering, so here\u2019s a nice simple <a href=\"https:\/\/reactjs.org\/docs\/components-and-props.html#functional-and-class-components\">React functional component<\/a> for us to pretend we would ever want to see:<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ app\/javascript\/components\/HelloWorld.jsx<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">React<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"kd\">function<\/span> <span class=\"nx\">HelloWorld<\/span><span class=\"p\">({<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"nx\">color<\/span><span class=\"p\">,<\/span> <span class=\"nx\">shape<\/span><span class=\"p\">})<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return<\/span> <span class=\"p\">(<\/span>\n    <span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>\n      Hi <span class=\"si\">{<\/span><span class=\"nx\">name<\/span><span class=\"si\">}<\/span>, your favourite color is <span class=\"si\">{<\/span><span class=\"nx\">color<\/span><span class=\"si\">}<\/span> and shape is <span class=\"si\">{<\/span><span class=\"nx\">shape<\/span><span class=\"si\">}<\/span>\n    <span class=\"p\">&lt;\/<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>\n  <span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now lets render the component! This won\u2019t work yet as we haven\u2019t told Hypernova how to find the component, but I think it\u2019s easier to understand the component registration system when you start from the outside. The syntax Hypernova client provides is real simple, a unique identifier for your component, and a props hash that the client will serialize + de-serialize, parsing into your component as regular props:<\/p>\n\n<div class=\"language-erb highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"cp\">&lt;%=<\/span>\n  <span class=\"n\">render_react_component<\/span><span class=\"p\">(<\/span>\n    <span class=\"s1\">'HelloWorld'<\/span><span class=\"p\">,<\/span>\n    <span class=\"ss\">name: <\/span><span class=\"s1\">'Person'<\/span><span class=\"p\">,<\/span>\n    <span class=\"ss\">color: <\/span><span class=\"s1\">'Blue'<\/span><span class=\"p\">,<\/span>\n    <span class=\"ss\">shape: <\/span><span class=\"s1\">'Triangle'<\/span>\n  <span class=\"p\">)<\/span>\n<span class=\"cp\">%&gt;<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>But as I say, we need to teach Hypernova where to get our component when it receives \u201cHelloWorld\u201d. Your pack must call <code class=\"language-plaintext highlighter-rouge\">renderReact()<\/code> with the name you wish to use to render your component(s), and the component that will render. Later we\u2019ll find it must also <em>export<\/em> the component for server side rendering, so we\u2019ll go ahead and do that right now:<\/p>\n\n<div class=\"language-jsx highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ app\/javascript\/packs\/react-hypernova.js<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">React<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">renderReact<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">hypernova-react<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"nx\">HelloWorldComponent<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">..\/components\/HelloWorld<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">HelloWorld<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">renderReact<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">HelloWorld<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"nx\">HelloWorldComponent<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Right now you should be able to load your template, and find your component rendering just fine, even though we haven\u2019t set up the server yet!<\/p>\n\n<h3 id=\"step-3-server-side-rendering\">Step 3: Server Side Rendering<\/h3>\n\n<p>If you view source on your existing work, you should find that your component is a single <code class=\"language-plaintext highlighter-rouge\">div<\/code>, with some data attributes, but we want to replace that with the whole component\u2019s DOM, pre-rendered server side, so lets get to it.<\/p>\n\n<p>First up, lets add the <a href=\"https:\/\/github.com\/airbnb\/hypernova\">Hypernova server<\/a> and webpack-merge to our JS dependencies, as we\u2019ll need both later:<\/p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>yarn add hypernova webpack-merge\n<\/code><\/pre><\/div><\/div>\n\n<p>Next, we\u2019ll need to do some damage to our webpacker config to build a version that Node can handle. This will ensure that dependencies that rely on browser APIs and don\u2019t crash the server, at least in most cases. I had to do this for instance for the <a href=\"https:\/\/github.com\/mapbox\/mapbox-gl-js\">Mapbox GL<\/a> package, which uses WebGL APIs, but knows to short circuit if it detects it is not in a browser environment.<\/p>\n\n<p><strong>[Note] Webpacker and Webpack are on the verge of some major changes, so its quite likely that when you read this, its outdated. Sorry, thats JS for you :(<\/strong><\/p>\n\n<p>We\u2019re going to add a new webpack config to <code class=\"language-plaintext highlighter-rouge\">config\/webpack<\/code>, based on our shared <code class=\"language-plaintext highlighter-rouge\">environment<\/code> config, but targeting node, and outputting a file with a predictable path (no fingerprinting) so we can fetch it server side without issue:<\/p>\n\n<div class=\"language-js highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ config\/webpack\/server.js<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">environment<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.\/environment<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">merge<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">webpack-merge<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\">\/\/ React Server Side Rendering webpacker config<\/span>\n<span class=\"c1\">\/\/ Builds a Node compatible file that Hypernova can load, never served to the client.<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">serverEnvironment<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">merge<\/span><span class=\"p\">(<\/span><span class=\"nx\">environment<\/span><span class=\"p\">.<\/span><span class=\"nx\">toWebpackConfig<\/span><span class=\"p\">(),<\/span> <span class=\"p\">{<\/span>\n  <span class=\"na\">target<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">node<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">entry<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/app\/javascript\/packs\/react-hypernova.js<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">output<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"na\">filename<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">server.js<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">path<\/span><span class=\"p\">:<\/span> <span class=\"nx\">environment<\/span><span class=\"p\">.<\/span><span class=\"nx\">config<\/span><span class=\"p\">.<\/span><span class=\"nx\">output<\/span><span class=\"p\">.<\/span><span class=\"nx\">path<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">libraryTarget<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">commonjs<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n  <span class=\"p\">},<\/span>\n<span class=\"p\">})<\/span>\n\n<span class=\"c1\">\/\/ This removes the Manifest from the Server.<\/span>\n<span class=\"c1\">\/\/ Manifest overwrites the _real_ client manifest, required by Rails.<\/span>\n<span class=\"nx\">serverEnvironment<\/span><span class=\"p\">.<\/span><span class=\"nx\">plugins<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">serverEnvironment<\/span><span class=\"p\">.<\/span><span class=\"nx\">plugins<\/span>\n  <span class=\"p\">.<\/span><span class=\"nx\">filter<\/span><span class=\"p\">(<\/span><span class=\"nx\">plugin<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">plugin<\/span><span class=\"p\">.<\/span><span class=\"kd\">constructor<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span> <span class=\"o\">!==<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">ManifestPlugin<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nx\">module<\/span><span class=\"p\">.<\/span><span class=\"nx\">exports<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">serverEnvironment<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>And we\u2019re going to add that <code class=\"language-plaintext highlighter-rouge\">server.js<\/code> config to our development and production builds, by replacing the <code class=\"language-plaintext highlighter-rouge\">module.exports<\/code> with an <em>array<\/em>, which webpack supports:<\/p>\n\n<div class=\"language-js highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ config\/webpack\/development.js<\/span>\n<span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">NODE_ENV<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">NODE_ENV<\/span> <span class=\"o\">||<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">development<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">environment<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.\/environment<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">serverConfig<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.\/server<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nx\">module<\/span><span class=\"p\">.<\/span><span class=\"nx\">exports<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"nx\">environment<\/span><span class=\"p\">.<\/span><span class=\"nx\">toWebpackConfig<\/span><span class=\"p\">(),<\/span> <span class=\"nx\">serverConfig<\/span><span class=\"p\">]<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<div class=\"language-js highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ config\/webpack\/production.js<\/span>\n<span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">NODE_ENV<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">NODE_ENV<\/span> <span class=\"o\">||<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">production<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">environment<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.\/environment<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">serverConfig<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.\/server<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nx\">module<\/span><span class=\"p\">.<\/span><span class=\"nx\">exports<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"nx\">environment<\/span><span class=\"p\">.<\/span><span class=\"nx\">toWebpackConfig<\/span><span class=\"p\">(),<\/span> <span class=\"nx\">serverConfig<\/span><span class=\"p\">]<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now that we have a file that Hypernova server can read, we need to create a script to run the server, and provide it the necessary logic to resolve a component name to a React component. Recall that we configured Rails to look for Hypernova on port 3030, so we\u2019ll copy that here.<\/p>\n\n<div class=\"language-js highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\">\/\/ script\/hypernova.js<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">hypernova<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">hypernova\/server<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">env<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">NODE_ENV<\/span> <span class=\"o\">||<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">development<\/span><span class=\"dl\">\"<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">devMode<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">env<\/span> <span class=\"o\">===<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">development<\/span><span class=\"dl\">\"<\/span>\n\n<span class=\"nx\">hypernova<\/span><span class=\"p\">({<\/span>\n  <span class=\"c1\">\/\/ Enabling devMode is important because it renders server errors to the<\/span>\n  <span class=\"c1\">\/\/ DOM, allowing you to know when SSR is failing, and why.<\/span>\n  <span class=\"nx\">devMode<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">port<\/span><span class=\"p\">:<\/span> <span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">HYPERNOVA_PORT<\/span> <span class=\"o\">||<\/span> <span class=\"mi\">3030<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">getComponent<\/span><span class=\"p\">:<\/span> <span class=\"nx\">name<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Allow iteration in dev, because require is cached otherwise<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">devMode<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">delete<\/span> <span class=\"nx\">require<\/span><span class=\"p\">.<\/span><span class=\"nx\">cache<\/span><span class=\"p\">[<\/span><span class=\"nx\">require<\/span><span class=\"p\">.<\/span><span class=\"nx\">resolve<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">..\/public\/packs\/server.js<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)]<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"kd\">let<\/span> <span class=\"nx\">componentMap<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">..\/public\/packs\/server.js<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">componentMap<\/span><span class=\"p\">[<\/span><span class=\"nx\">name<\/span><span class=\"p\">])<\/span> <span class=\"k\">return<\/span> <span class=\"nx\">componentMap<\/span><span class=\"p\">[<\/span><span class=\"nx\">name<\/span><span class=\"p\">]<\/span>\n    <span class=\"k\">throw<\/span> <span class=\"k\">new<\/span> <span class=\"nb\">Error<\/span><span class=\"p\">(<\/span>\n      <span class=\"s2\">`Could not find component named <\/span><span class=\"p\">${<\/span><span class=\"nx\">name<\/span><span class=\"p\">}<\/span><span class=\"s2\"> in packs\/react-hypernova.js, ensure you exported it with the name <\/span><span class=\"p\">${<\/span><span class=\"nx\">name<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span>\n    <span class=\"p\">)<\/span>\n  <span class=\"p\">},<\/span>\n<span class=\"p\">})<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Now, when you run your server with <code class=\"language-plaintext highlighter-rouge\">node script\/hypernova.js<\/code>, and refresh your browser, you should find that your page source includes your pre-rendered component!<\/p>\n\n<p>When it comes to production, you\u2019ll need a way to ensure this script is called with the appropriate RAILS_ENV and NODE_ENV environment variables, and is run on startup. A simple &lt; init system of choice &gt; script should do the trick.<\/p>\n\n<h3 id=\"4-production-health-checks\">4. Production Health Checks<\/h3>\n\n<p>We could stop here, but there\u2019s one more piece I recommend adding. The downside of Hypernova\u2019s resiliency is that an engineer could break SSR, and no one would know, because your site would still work fine. To counter that, lets use Hypernova client\u2019s plugin system to let ourselves how things are working:<\/p>\n\n<div class=\"language-ruby highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c1\"># Append this to:<\/span>\n<span class=\"c1\"># config\/initializers\/hypernova.rb<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">HypernovaRequestMonitoring<\/span>\n  <span class=\"k\">def<\/span> <span class=\"nf\">prepare_request<\/span><span class=\"p\">(<\/span><span class=\"n\">current_request<\/span><span class=\"p\">,<\/span> <span class=\"n\">original_request<\/span><span class=\"p\">)<\/span>\n    <span class=\"c1\"># This is a good place to increment internal counters to know that a request happened<\/span>\n    <span class=\"n\">current_request<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nf\">after_response<\/span><span class=\"p\">(<\/span><span class=\"n\">current_response<\/span><span class=\"p\">,<\/span> <span class=\"n\">original_response<\/span><span class=\"p\">)<\/span>\n    <span class=\"c1\"># This is a good place to increment internal counters to know that a request was successful<\/span>\n    <span class=\"n\">current_response<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nf\">on_error<\/span><span class=\"p\">(<\/span><span class=\"n\">error<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n    <span class=\"c1\"># This is a good place to send SSR render errors to your error tracking system, or log it<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n\n<span class=\"no\">Hypernova<\/span><span class=\"p\">.<\/span><span class=\"nf\">add_plugin!<\/span><span class=\"p\">(<\/span><span class=\"no\">HypernovaRequestMonitoring<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre><\/div><\/div>\n\n<p>Personally we use this to instrument with some Datadog dogstatsd metrics, log errors in development, and report errors to Sentry in production.<\/p>\n\n<h3 id=\"conclusion\">Conclusion<\/h3>\n\n<p>Alright! You <em>should<\/em> now have a Rails + React + Webpacker + Hypernova setup, with SSR working a treat. If you don\u2019t, its probably because I extracted this 101 tutorial from a more complicated project, and missed a part. Please leave a comment, and I will do my best to correct any mistakes quickly. If it\u2019s not that, then you might like me be the victim of constant change in Webpack + Webpacker. At time or writing, Webpacker 4.0 is in pre-release, hopefully it doesn\u2019t change too much!<\/p>\n\n<p>Thanks for reading,<\/p>\n\n<p>Matt<\/p>\n","pubDate":"Sat, 04 Aug 2018 17:32:00 +0000","link":"https:\/\/bessey.dev\/blog\/2018\/08\/04\/rails-webpacker-react-ssr\/","guid":"https:\/\/bessey.dev\/blog\/2018\/08\/04\/rails-webpacker-react-ssr\/","category":["ruby","rails","react","hypernova","ssr","server side rendering"]},{"title":"Easy SuckerPunch Asynchronous Mailers ","description":"<p>For a Rails side project recently I finally had the need for a background task handler. Now traditionally I\u2019d jump at <a href=\"http:\/\/sidekiq.org\/\">Sidekiq<\/a>, and for good reason. It\u2019s sexy, relatively simple, and comes with a ton of niceties like automatic exponential back-off retries. For this project however, at least at this stage, Sidekiq is overkill. We just need to run some ActionMailers out of the render loop, so we\u2019d like to avoid booting up another server if possible.<\/p>\n\n<p>So, in comes <a href=\"https:\/\/github.com\/brandonhilkert\/sucker_punch\">SuckerPunch<\/a>, a gem built to address exactly this issue. SuckerPunch uses <a href=\"https:\/\/github.com\/celluloid\/celluloid\/\">Celluloid<\/a> to operate a barebones background task handler <em>inside the server process<\/em>, avoiding the significant memory overhead of running two Rails instances. Now while its worth noting thanks to the Global Interpreter Lock present in MRI, CPU intensive jobs are still liable to slow down your requests, however the GIL does not apply to external I\/O, and so the bulk of what makes a mailer slow (negotiating SMTP) <strong>doesn\u2019t block the server<\/strong>.<\/p>\n\n<!-- more -->\n\n<p>This is great! So now we just need to write a load of jobs for each mailer method we want to run in the background, like so:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"c1\"># jobs\/user_mailer_job.rb<\/span>\n<span class=\"k\">class<\/span> <span class=\"nc\">UserRegistrationMailerJob<\/span>\n  <span class=\"kp\">include<\/span> <span class=\"no\">SuckerPunch<\/span><span class=\"o\">::<\/span><span class=\"no\">Job<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nf\">perform<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"p\">)<\/span>\n    <span class=\"no\">UserMailer<\/span><span class=\"p\">.<\/span><span class=\"nf\">registration<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"p\">).<\/span><span class=\"nf\">deliver<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span><\/code><\/pre><\/figure>\n\n<h3 id=\"refactor-refactor-refactor\">Refactor, refactor, refactor!<\/h3>\n\n<p>Clean as this DSL is, its clearly going to get unwieldy. It would be much nicer to be able to have a job that could handle <em>any<\/em> email for <em>any<\/em> mailer. Fortunately this isn\u2019t too hard to achieve with just a pinch of meta-programming:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"c1\"># jobs\/async_mailer_job.rb<\/span>\n<span class=\"k\">class<\/span> <span class=\"nc\">AsyncMailerJob<\/span>\n  <span class=\"kp\">include<\/span> <span class=\"no\">SuckerPunch<\/span><span class=\"o\">::<\/span><span class=\"no\">Job<\/span>\n\n  <span class=\"c1\"># Enables us to turn any mailer into an asyncronous one<\/span>\n  <span class=\"k\">def<\/span> <span class=\"nf\">perform<\/span><span class=\"p\">(<\/span><span class=\"n\">mailer<\/span><span class=\"p\">,<\/span> <span class=\"nb\">method<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n    <span class=\"no\">Rails<\/span><span class=\"p\">.<\/span><span class=\"nf\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"Asyncronously running <\/span><span class=\"si\">#{<\/span><span class=\"n\">mailer<\/span><span class=\"p\">.<\/span><span class=\"nf\">to_s<\/span><span class=\"si\">}<\/span><span class=\"s2\">.<\/span><span class=\"si\">#{<\/span><span class=\"nb\">method<\/span><span class=\"p\">.<\/span><span class=\"nf\">to_s<\/span><span class=\"si\">}<\/span><span class=\"s2\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">mailer<\/span><span class=\"p\">.<\/span><span class=\"nf\">send<\/span><span class=\"p\">(<\/span><span class=\"nb\">method<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">).<\/span><span class=\"nf\">deliver<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span><\/code><\/pre><\/figure>\n\n<p>Now we can slightly modify our existing mailer calls slightly to achieve the same effect as before, without a specific job for each of them:<\/p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">AsyncMailerJob.new.async.perform(UserMailer, :registration, user)<\/code><\/p>\n\n<h3 id=\"but-wait-theres-more\">But wait, there\u2019s more!<\/h3>\n\n<p>Hmmm, it seems we can do a little better than that though. The syntax is a little ugly, wouldn\u2019t it be nice if all we had to do to run a mailer asynchronously was (like with SuckerPunch jobs) add an <code class=\"language-plaintext highlighter-rouge\">.async<\/code> call before calling the message method? If we knock the meta-programming dial up a notch this isn\u2019t actually too difficult. First up we need to build a module that defines the <code class=\"language-plaintext highlighter-rouge\">.async<\/code> method on a mailer, lets not worry about whats going in there for now:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"c1\"># async_mailer.rb<\/span>\n\n<span class=\"k\">module<\/span> <span class=\"nn\">AsyncMailer<\/span>\n  <span class=\"k\">module<\/span> <span class=\"nn\">ClassMethods<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">async<\/span>\n      <span class=\"no\">AsyncMailerJobRunner<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"nb\">self<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">end<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nc\">self<\/span><span class=\"o\">.<\/span><span class=\"nf\">included<\/span><span class=\"p\">(<\/span><span class=\"n\">base<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">base<\/span><span class=\"p\">.<\/span><span class=\"nf\">extend<\/span> <span class=\"no\">ClassMethods<\/span>\n  <span class=\"k\">end<\/span>\n\n<span class=\"k\">end<\/span><\/code><\/pre><\/figure>\n\n<p>Nothing too crazy yet, just using the <code class=\"language-plaintext highlighter-rouge\">included<\/code> callback to allow a module to define methods on the class (as opposed to instances of the class). So what\u2019s going in <code class=\"language-plaintext highlighter-rouge\">async<\/code>? Lets look at the <code class=\"language-plaintext highlighter-rouge\">AsyncMailerJobRunner<\/code> to find out:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"c1\"># async_mailer_job_runner.rb<\/span>\n<span class=\"k\">class<\/span> <span class=\"nc\">AsyncMailerJobRunner<\/span>\n  <span class=\"k\">def<\/span> <span class=\"nf\">initialize<\/span><span class=\"p\">(<\/span><span class=\"n\">mailer<\/span><span class=\"p\">)<\/span>\n    <span class=\"vi\">@mailer<\/span> <span class=\"o\">=<\/span> <span class=\"n\">mailer<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nf\">method_missing<\/span><span class=\"p\">(<\/span><span class=\"n\">meth<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">,<\/span> <span class=\"o\">&amp;<\/span><span class=\"n\">block<\/span><span class=\"p\">)<\/span>\n    <span class=\"no\">AsyncMailerJob<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">.<\/span><span class=\"nf\">async<\/span><span class=\"p\">.<\/span><span class=\"nf\">perform<\/span><span class=\"p\">(<\/span><span class=\"vi\">@mailer<\/span><span class=\"p\">,<\/span> <span class=\"n\">meth<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span><\/code><\/pre><\/figure>\n\n<p>Remember <code class=\"language-plaintext highlighter-rouge\">async<\/code> has to return an object that <strong>acts like a mailer<\/strong> while actually running the mailer commands asynchronously. To do that, it effectively mocks a mailer, delegating all messages not to the mailer, but instead to the <code class=\"language-plaintext highlighter-rouge\">AsyncMailerJob<\/code> we wrote earlier. Thanks to <code class=\"language-plaintext highlighter-rouge\">method_missing<\/code> we don\u2019t have to worry about which mailer method is called, and thanks to splat <code class=\"language-plaintext highlighter-rouge\">*args<\/code> we don\u2019t have to worry about that method\u2019s footprint. Meta-programming at its most finest!<\/p>\n\n<p>I hope all that was helpful to you. If you see any improvements or errata please throw me a comment! For the lazier here\u2019s the source all together in its entirety:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"c1\"># mailers\/async_mailer.rb<\/span>\n\n<span class=\"c1\"># Gives an ActionMailer the ability to run any method asynchronously by simply<\/span>\n<span class=\"c1\"># prepending an .async call.<\/span>\n<span class=\"c1\">#<\/span>\n<span class=\"c1\"># Example:<\/span>\n<span class=\"c1\">#   MyMailer.async.new_user_email(user)<\/span>\n\n<span class=\"k\">module<\/span> <span class=\"nn\">AsyncMailer<\/span>\n  <span class=\"c1\"># Takes care of transforming an ActionMailer method call into a SuckerPunch<\/span>\n  <span class=\"c1\"># perform call.<\/span>\n  <span class=\"c1\">#<\/span>\n  <span class=\"c1\"># Example:<\/span>\n  <span class=\"c1\">#   MyMailer.new_user_email(user)<\/span>\n  <span class=\"c1\"># becomes<\/span>\n  <span class=\"c1\">#   AsyncMailerJob.new.async.perform(MyMailer, :new_user_email, user)<\/span>\n\n  <span class=\"k\">class<\/span> <span class=\"nc\">AsyncMailerJobRunner<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">initialize<\/span><span class=\"p\">(<\/span><span class=\"n\">mailer<\/span><span class=\"p\">)<\/span>\n      <span class=\"vi\">@mailer<\/span> <span class=\"o\">=<\/span> <span class=\"n\">mailer<\/span>\n    <span class=\"k\">end<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">method_missing<\/span><span class=\"p\">(<\/span><span class=\"n\">meth<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">,<\/span> <span class=\"o\">&amp;<\/span><span class=\"n\">block<\/span><span class=\"p\">)<\/span>\n      <span class=\"no\">AsyncMailerJob<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">.<\/span><span class=\"nf\">async<\/span><span class=\"p\">.<\/span><span class=\"nf\">perform<\/span><span class=\"p\">(<\/span><span class=\"vi\">@mailer<\/span><span class=\"p\">,<\/span> <span class=\"n\">meth<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">end<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">class<\/span> <span class=\"nc\">AsyncMailerJob<\/span>\n    <span class=\"kp\">include<\/span> <span class=\"no\">SuckerPunch<\/span><span class=\"o\">::<\/span><span class=\"no\">Job<\/span>\n\n    <span class=\"c1\"># Enables us to turn any mailer into an asyncronous one<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">perform<\/span><span class=\"p\">(<\/span><span class=\"n\">mailer<\/span><span class=\"p\">,<\/span> <span class=\"nb\">method<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n      <span class=\"no\">Rails<\/span><span class=\"p\">.<\/span><span class=\"nf\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"Asyncronously running <\/span><span class=\"si\">#{<\/span><span class=\"n\">mailer<\/span><span class=\"p\">.<\/span><span class=\"nf\">to_s<\/span><span class=\"si\">}<\/span><span class=\"s2\">.<\/span><span class=\"si\">#{<\/span><span class=\"nb\">method<\/span><span class=\"p\">.<\/span><span class=\"nf\">to_s<\/span><span class=\"si\">}<\/span><span class=\"s2\">\"<\/span><span class=\"p\">)<\/span>\n      <span class=\"n\">mailer<\/span><span class=\"p\">.<\/span><span class=\"nf\">send<\/span><span class=\"p\">(<\/span><span class=\"nb\">method<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">).<\/span><span class=\"nf\">deliver<\/span>\n    <span class=\"k\">end<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">module<\/span> <span class=\"nn\">ClassMethods<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">async<\/span>\n      <span class=\"no\">AsyncMailerJobRunner<\/span><span class=\"p\">.<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"nb\">self<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">end<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nc\">self<\/span><span class=\"o\">.<\/span><span class=\"nf\">included<\/span><span class=\"p\">(<\/span><span class=\"n\">base<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">base<\/span><span class=\"p\">.<\/span><span class=\"nf\">extend<\/span> <span class=\"no\">ClassMethods<\/span>\n  <span class=\"k\">end<\/span>\n\n<span class=\"k\">end<\/span><\/code><\/pre><\/figure>\n\n<p>Enjoy!<\/p>\n","pubDate":"Wed, 14 May 2014 23:27:00 +0000","link":"https:\/\/bessey.dev\/blog\/2014\/05\/14\/easy-asynchronous-mailers-with-suckerpunch\/","guid":"https:\/\/bessey.dev\/blog\/2014\/05\/14\/easy-asynchronous-mailers-with-suckerpunch\/","category":["ruby","rails","suckerpunch"]},{"title":"I, Car","description":"<p>The topic that\u2019s got me - and it seems a great deal of others - hot under the collar lately is that of the \u2018self driving\u2019 car. As Google and others further the technology necessary for a world free from steering wheels, one can\u2019t help but wonder just what that world will be like. Many have dabbled in this topic but I hope to raise some points here I\u2019ve not myself heard.<\/p>\n\n<!-- more -->\n\n<h3 id=\"resistance\">Resistance<\/h3>\n<p>While we\u2019ve come along way since the <em>Y2K<\/em> world, a time when people had a natural distrust for machines (seriously, it seems so ridiculous now, but I\u2019m sure you can recall just as I do a time when adults held a genuine distrust for a <em>computer<\/em>). Now, finally, people have started having reasonable faith in glorified logic machines and are instead recognizing the people operating them are the ones increasingly often not to be trusted. As of late, the people most often in the spotlight of course are not drivers but rather the NSA. Still, the point stands; to quote a wonderful acronym coined in tech support circles, P.L.B.K.A.C: Problem Lies Between Keyboard And Chair. So surely if we take away the <del>keyboard<\/del> steering wheel, no one could take objection?<\/p>\n\n<p>Fortunately, even if for whatever reason there is resistance to the concept, its not a topic we have to convince the world of all at once. As much as I wish I could say in a years time the roads will be filled (or indeed empty) with fully autonomous vehicles, the reality of this situation is we\u2019re much more likely to get there via a few intermediary steps.<\/p>\n\n<p>We\u2019ll start, or rather we <em>have<\/em> started with computer assisted driving. Already cars are on the roads that can park themselves, <a href=\"https:\/\/www.youtube.com\/watch?v=Pl1UMfxa_r4\">emergency stop<\/a>, warn you of a vehicle in your blind spot, and more features are added constantly. The next step of course is to switch roles; <strong>human<\/strong> assisted driving, systems akin to what Google is <a href=\"https:\/\/www.youtube.com\/watch?v=cdgQpa1pUUE\">already testing on the streets<\/a>. We\u2019ll likely stay at this stage until the vast majority of <em>things<\/em> on the road are autonomous.<\/p>\n\n<p>Eventually though, we\u2019ll get to that wonderful point, where we can eliminate even the occasional need for a human at the helm. And thats the time I\u2019d like to focus on, when things get really interesting.<\/p>\n\n<h3 id=\"starting-from-scratch\">Starting from scratch<\/h3>\n<p>Once you\u2019ve taken the driver out of the equation, the distinction between public and private transportation is bound to change. When a vehicle can drive itself, does it make sense for one individual or even household to own one? I certainly don\u2019t think it does. It makes much more sense for the bare minimum number of vehicles needed to serve a populace to be in constant circulation than it does for <em>your<\/em> car to be parked outside <em>your<\/em> house waiting for <em>you<\/em>. This change will be much akin to how Toyota turned car manufacturing on its head with its <a href=\"http:\/\/en.wikipedia.org\/wiki\/Kanban\">Kanban process<\/a>, moving an entire industry from stockpiling resources to instead maintaining the bare minimum of inventory needed for peak production, a system which they showed vastly improves efficiency.<\/p>\n\n<p>Such a system brings several benefits. Firstly, fewer parked vehicles, one I have already touched on. In addition, we can expect more vehicle diversity; no longer is it necessary to take a stab at guessing what <strong>single<\/strong> vehicle will best suit your needs for the next 5+ years, and in doing so compromise on suiting any of them. Long gone will be the age of the 5 seater hatchback! Say hello instead to the all electric <strong>BatchelorPod<\/strong>, a single seater with an even smaller footprint than a Smart car. Once you tailor the vehicles on the road to accommodate precisely the number of people and baggage that want to <strong>be<\/strong> on the road, you reduce the total footprint hugely! This was recently and excellently demonstrated in a gif doing the rounds on tumblr:<\/p>\n\n<p><img src=\"\/images\/car_tram.gif\" alt=\"Car drivers fitting in a single tram car\" \/><\/p>\n\n<p>And once that hurdle is cleared, once we relinquish ownership of an individual vehicle for the betterment of everyone in the system, we eliminate the car as a status symbol, gleefully crushing in my mind at least a ridiculous industry built around designing an object - who\u2019s purpose is primarily functional - to instead best represent its owner.<\/p>\n\n<p>That isn\u2019t to say the automotive design industry is over. Far from it. Rather, their industry just received a tremendous breath of fresh air. Much of the design of a car once restricted by safety regulation is now gone! Windows? Seats that face forward? A dashboard? All these things are entirely irrelevant in this bold future. It seems to me car designers jobs are going to get a lot closer to Tony Stark\u2019s; purpose building \u201csuits\u201d to transport or even entertain their precious cargo.<\/p>\n\n<h3 id=\"the-three-laws-of-robotics\">The Three Laws of Robotics<\/h3>\n<p>Isaac Asimov\u2019s coined the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Three_Laws_of_Robotics\">three laws of robotics<\/a> in his <em>I, Robot<\/em> series. While I\u2019m sure he never intended for them to be taken as gospel outside of the world of science fiction, they are sensible and perhaps obvious laws that are bound to find there way into cars. Of particular interest in the context of autonomous vehicles is the first law:<\/p>\n\n<ol>\n  <li>A robot <strong>may not injure a human being<\/strong> or, through inaction, <strong>allow a human being to come to harm<\/strong>.<\/li>\n<\/ol>\n\n<p>Substitute \u201crobot\u201d for \u201chuman\u201d and I think you and I could both agree that the law should still stand, and by that logic one couldn\u2019t have much issue with it. But I foresee an interesting predicament that given enough time is bound to present itself, that is, a situation in which an autonomous vehicle <strong>does not<\/strong> make the same decision that its driver would have, in order to harm <em>fewer<\/em> lives than a self preserving human would. It is in our nature to be self preserving, and it is entirely plausible that a situation could arise on the road where in order to prevent a larger fatal accident from occurring, a driver would need to sacrifice themself. An obvious example would be two children running into the road, or catastrophic failure in a nearby much larger vehicle.<\/p>\n\n<p>And this raises an interesting issue: If I am the passenger in that autonomous car, sealed in, blissfully unaware of my surroundings and the situation about to arise ahead\u2026 Is it acceptable for my life to be ended to save others? Are there certain circumstances when it is and isn\u2019t? These are questions that as a society, we will have no choice but to come to a preemptive conclusion on, lest we leave it too late.<\/p>\n\n<h3 id=\"onwards-and-upwards\">Onwards and upwards<\/h3>\n<p>That concludes my thoughts worth mentioning on the brave new world we are entering. I hope that, having finished somewhat ominously on the ethics of robotics, you don\u2019t think I <em>fear<\/em> this future. Au contraire! I for one welcome our new steering wheel free overlords. I cannot wait to live in this mad and exciting future that will undoubtedly soon be reality.<\/p>\n\n<h5 id=\"matt\">Matt.<\/h5>\n","pubDate":"Wed, 12 Feb 2014 23:20:00 +0000","link":"https:\/\/bessey.dev\/blog\/2014\/02\/12\/i-car\/","guid":"https:\/\/bessey.dev\/blog\/2014\/02\/12\/i-car\/","category":["thoughts","futurism"]},{"title":"What they don't prepare you for","description":"<p>Time for some serious business. Buzzfeed level serious. Today we\u2019re talking about something a Brit holds dear and oft claims Americans do not. Today we\u2019re talking about\u2026 <strong>chocolate<\/strong>. One of the many things friends and family repeatadly warn you of before flying out is invariably how shit the chocolate in America is. \u201cThey put weird stuff in it! Anti melting agents!\u201d they say. Well of course, they\u2019re right. And you would to if you wanted to eat chocolate as opposed to brown peanut soup when you opened your Snickers wrapper. But that\u2019s not the crux of the chocolate issue. No there is in fact an entirely different offender that no one warns you of\u2026<\/p>\n\n<!-- more -->\n\n<h3 id=\"a-choc-by-any-other-name\">A Choc By Any Other Name<\/h3>\n\n<p>In the US, this passes for a Milky Way bar:<\/p>\n\n<p><img src=\"\/images\/choc\/milky_way.jpg\" alt=\"An American Milky Way bar\" \/><\/p>\n\n<p>Now I know what you\u2019re thinking. Well, if you\u2019re British and have <em>any<\/em> self respect, you\u2019re thinking \u201cWhat is this bullshit? That\u2019s a Mars bar!\u201d. You\u2019re damn right its a Mars bar. <strong>This, people<\/strong>, this is what you should be warned of at Heathrow.<\/p>\n\n<p>If you actually want a Milky Way, you\u2019ll have to turn to the likes of a \u20183 Musketeers\u2019:<\/p>\n\n<p><img src=\"\/images\/choc\/3_musketeers.jpeg\" alt=\"3 Musketeers bar\" \/><\/p>\n\n<p>But it just feels wrong, chomping down on this\u2026 this <strong>imposter<\/strong>, knowing full well his fluffy goodness doesn\u2019t belong here, but instead in star covered blue wrapper. The wrapper that he <em>deserves<\/em>.<\/p>\n","pubDate":"Sun, 24 Nov 2013 15:06:00 +0000","link":"https:\/\/bessey.dev\/blog\/2013\/11\/24\/what-they-dont-prepare-you-for\/","guid":"https:\/\/bessey.dev\/blog\/2013\/11\/24\/what-they-dont-prepare-you-for\/","category":["svip","america","chocolate"]},{"title":"Pivot early, pivot often","description":"<h2 id=\"this-is-how-the-weekend-began\">This is how the weekend began.<\/h2>\n\n<p><img src=\"\/images\/launch_energy.jpg\" alt=\"The hacking room\" \/><\/p>\n\n<p>Its been a few days since the 48 hour coding grind that was the <a href=\"http:\/\/hackathon.launch.co\">Launch Hackathon<\/a>, and I think I\u2019ve caught up on enough sleep to attempt a cohesive paragraph or two. Launch prided itself on being the largest hackathon ever, with 1,500 applicants. They didn\u2019t <em>all<\/em> show, but it was certainly huge.<\/p>\n\n<!-- more -->\n\n<p><img src=\"\/images\/launch_crowd.jpg\" alt=\"The hacking room\" \/><\/p>\n\n<p>That room is where I spent the entirety of my weekend. From Friday to Sunday night, this was my home. No beds, no showers, just me, my onesie, and my laptop. 10 of the SVIP crew took part, split into 3 teams, so we represented the brand well!<\/p>\n\n<p>I try to avoid \u201cthis is what I done did today\u201d posts, and today\u2019s is no different. There\u2019s not much to tell without getting into technical details; we came up with an idea or two a week prior, and then worked hard on it for two days, with about 3 hours sleep on each. In the end we royally fucked up and realised with 4 hours to go that we wouldn\u2019t have something presentable. So we pivoted (hence the title). We completely changed idea and, one man down thanks to exhaustion, tried to hammer that out. Predictably, we didn\u2019t get anything to a presentable state there either, but hey, <em>#yolo<\/em>. I had great fun building it and learnt a lot along the way.<\/p>\n\n<p><img src=\"\/images\/launch_me.jpg\" alt=\"Working hard, or hardly working?\" \/><\/p>\n\n<p>The winners, if you\u2019re curious, essentially made <a href=\"http:\/\/www.ramen.is\">Kickstarter for Startups<\/a> which ain\u2019t a bad idea by any means.<\/p>\n\n<p>One of the things I found most interesting about the whole Launch experience and the week of planning leading up to it was how full of ideas everyone was. About 10 of us met up at LoopUp\u2019s HQ for a Launch planning session, and nearly everyone had an idea, and they were invariably good ideas! Maybe I\u2019ve just become more of a\u2026 <em>Valley victim<\/em> shall we say, and lost my British cynicism, but it seems like even amongst us, the imports, the proportion of people with at least one entrepreneurial idea is colossal. When I was recording my SVIP video with Lee long before flying out<sup>[1]<\/sup> he mentioned in his that he hoped to start some kind of startup of his own with the other SVIP members. Before that the idea hadn\u2019t even crossed my mind, but its seemingly more plausible every day.<\/p>\n\n<p>I feel like this should end with something poignant, so here goes\u2026 As Jay Z might [never] say, this one goes out to all my engineer homies. At planning, there were several ideas that cropped up that were too big for a hackathon, almost all in fact, as evidenced by our failure! But that didn\u2019t dismay anyone, far from it. The conversation segued smoothly to \u201cright, when shall we make that one?\u201d. The point is, its not about the hackathon. They are a means to an end, a great motivational tool, but that\u2019s it. If you have a Good Idea, don\u2019t be perturbed by irrelevant constraints\u2026<\/p>\n\n<h3 id=\"just-build-it\">Just build it.<\/h3>\n\n<p><strong>[1]<\/strong> Do NOT try and find that video. Dear god. No.<\/p>\n","pubDate":"Wed, 13 Nov 2013 23:14:00 +0000","link":"https:\/\/bessey.dev\/blog\/2013\/11\/13\/pivot-early\/","guid":"https:\/\/bessey.dev\/blog\/2013\/11\/13\/pivot-early\/","category":"svip"},{"title":"Greater than the sum of its parts","description":"<p>Up until now I\u2019ve found it hard to articulate exactly what it is that makes Silicon Valley such a different experience to the rest of the world, but after a few weeks of living it, I think I\u2019ve got it now. Let me take you through some of the mad things than happen here that are just considered normal to the locals.<\/p>\n\n<p>Firstly, the sheer density of tech workers here noticeably affects the culture of the area, particularly in marketing. Driving into SF on the freeway, you can expect to see billboard after billboard advertising tech conferences, services, and products, right alongside ads for Miller light beer. Here, tech companies have brands so respected that wearing a facebook or twitter or dropbox T-shirt around town is <em>nothing<\/em>, its just\u2026 normal. <!-- more --> The first time I wore my <a href=\"\/images\/nerdlife.png\">Nerd Life<\/a> T-shirt, (you get them free when you sign up to a server monitoring service, honest!) to work, another engineer on the team was wearing the same shirt! Faux pas aside, given that our Engineering team is fewer than 10 people, it serves to demonstrate the culture here.<\/p>\n\n<p>Although many startups have products based purely in the web, increasingly there seems to be a trend of businesses who\u2019s products bridge the gap between digital and analogue mediums. And since many of those startups are starting here, we tend to be the beta testers for them. And my god, are there some incredible products being trialled here. Probably the most amazing is <a href=\"http:\/\/www.lyft.me\/\">Lyft<\/a>, an app that literally lets anyone sign up to be a taxi driver, and let anyone call those taxi drivers from wherever they are. The process is so frictionless you\u2019d think you have your own private driver:<\/p>\n\n<ol>\n  <li>Open app, immediately on a map with a pin where you are, and a notice of the time it\u2019ll take the nearest taxi to get to you. We\u2019re talking less than 5 minutes if you\u2019re in central SF.<\/li>\n  <li>Press \u201cRequest Lyft\u201d, and get presented with a picture of your driver and his car, and his car icon will now appear on your map. All cars have a bright pink moustache on the front to help you look out for them.<\/li>\n  <li>Get in car when you see it arrive!<\/li>\n  <li>Get out at your destination. No payment, it happens automatically through the app.<\/li>\n<\/ol>\n\n<p>Its like living in the future, honestly. And it doesn\u2019t end there! Shopping too has been digitised to an even greater extent than in the UK, thanks to <a href=\"http:\/\/instacart.com\">Instacart<\/a> a service that lets you shop at one website for food from 4 separate supermarket chains. Not only that, but delivery time is way faster than the UK, generally 1-2 <strong>hours<\/strong>. And unlike in the UK, you\u2019ll be called before delivery begins with notification of substitutions so you can change them <em>before<\/em> they arrive.<\/p>\n\n<p>Even dating has been distilled into its purest form, thanks to <a href=\"http:\/\/www.gotinder.com\/\">Tinder<\/a>. I hear Tinder is picking up in the UK now, so perhaps you\u2019ve heard of it. If not, Tinder would be best described as a \u201chot or not\u201d app that ends in the two of you being put in contact if you both rate each other as \u201chot\u201d. The experience is so efficient its unsettling, though of course as with all dating services the gender ratio leans heavily toward men.<\/p>\n\n<h3 id=\"and-lastly-theres-the-work-flexibility\">And lastly, there\u2019s the work flexibility.<\/h3>\n\n<p><img src=\"\/images\/gotomeeting.jpg\" alt=\"Working Remotely Meeting\" \/><\/p>\n\n<p>Since the BART (Bay Area underground) was on strike on Friday, commuting would have been a pain in the arse, but fortunately tele-commuting is such a non-issue here that working the occasional day from home is no problem. Two of our engineering team actually tele-commute 95% of the time, as they don\u2019t even live in California!<\/p>\n\n<p>But here, no one bats an eyelid at any of this. It\u2019s just part of the package. And frankly, I <em>can\u2019t wait<\/em> for this package to catch on the world over.<\/p>\n","pubDate":"Sat, 19 Oct 2013 12:40:00 +0000","link":"https:\/\/bessey.dev\/blog\/2013\/10\/19\/greater-than-the-sum-of-its-parts\/","guid":"https:\/\/bessey.dev\/blog\/2013\/10\/19\/greater-than-the-sum-of-its-parts\/","category":"svip"}]}}