{"id":41507,"date":"2010-05-07T14:55:36","date_gmt":"2010-05-07T21:55:36","guid":{"rendered":"https:\/\/redfindevelop.wpengine.com\/blog\/devblog\/?p=302"},"modified":"2020-10-05T13:12:36","modified_gmt":"2020-10-05T20:12:36","slug":"synchronousasynchronous_switching_with_varnish","status":"publish","type":"post","link":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/","title":{"rendered":"Synchronous\/Asynchronous Switching with Varnish"},"content":{"rendered":"<p>When your webapp is serving up content that&#8217;s expensive to generate, you may want to serve it up asynchronously- via <a href=\"http:\/\/en.wikipedia.org\/wiki\/AJAX\" target=\"_new\" rel=\"noopener noreferrer\">AJAX<\/a> calls.  This is particularly appealing when content is &#8220;below <a href=\"http:\/\/en.wikipedia.org\/wiki\/Above_the_fold\" target=\"_new\" rel=\"noopener noreferrer\">the fold<\/a>.&#8221;<\/p>\n<p>However when that content is cached, you want to serve it up as quickly as possible.  If you&#8217;ve already calculated the content, you&#8217;d like to include it inline in the page, without requiring an AJAX roundtrip.  That way, you avoid the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Latency_(engineering)\" target=\"_new\" rel=\"noopener noreferrer\">latency<\/a> of an unnecessary round-trip.  You also allow the page to be fully rendered (so content doesn&#8217;t jump around), etc.<\/p>\n<p>You can optimize for the empty cache, or you can optimize for the full cache, but it seems hard to optimize both experiences.<\/p>\n<p>Redfin faces exactly this conundrum with our listing pages (e.g. <a href=\"https:\/\/redfin.com\/CA\/San-Francisco\/830-El-Camino-Del-Mar-94121\/home\/604622\" target=\"_new\" rel=\"noopener noreferrer\">https:\/\/redfin.com\/CA\/San-Francisco\/830-El-Camino-Del-Mar-94121\/home\/604622<\/a>.)  Calculating the Similar Listings and Similar Sales is expensive and performed in real time.  We cut this <a href=\"http:\/\/en.wikipedia.org\/wiki\/Gordian_Knot\" target=\"_new\" rel=\"noopener noreferrer\">Gordian Knot<\/a> through the use of the <a href=\"http:\/\/www.varnish-cache.org\/\" target=\"_new\" rel=\"noopener noreferrer\">Varnish<\/a> caching reverse proxy, along with clever use of ESI (<a href=\"http:\/\/en.wikipedia.org\/wiki\/Edge_Side_Includes\" target=\"_new\" rel=\"noopener noreferrer\">Edge Side Includes<\/a>.)  For an overview of how we use Varnish at Redfin, see our <a href=\"https:\/\/redfin.com\/blog\/devblog\/2010\/05\/esi_and_caching_trickery_in_varnish.html\" target=\"_new\" rel=\"noopener noreferrer\">previous post<\/a>.<\/p>\n<p><a href=\"http:\/\/en.wikipedia.org\/wiki\/Gordian_knot\" target=\"_new\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/b\/bb\/Alexander_cuts_the_Gordian_Knot.jpg\"\/><\/a><\/p>\n<p>We want to say &#8220;if there&#8217;s a cache miss, then do AJAX, but if there&#8217;s a cache hit, then just include the content.&#8221;  We have to make sure that the AJAX calls will fill the cache, such that subsequent requests will see cache hits, of course!<\/p>\n<p>I&#8217;ll outline what the requests\/responses look like for us, then I&#8217;ll include some pseudocode that supports this.<\/p>\n<p>At the beginning of time, the cache is empty, and the browser requests information on a Listing.<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"4\">\n<tr bgcolor=\"#e7e7e3\">\n<th>\n\t\t\tStep\n\t\t<\/th>\n<th>\n\t\t\tBrowser\n\t\t<\/th>\n<th>\n\t\t\tVarnish\n\t\t<\/th>\n<th>\n\t\t\tBackend Server\n\t\t<\/th>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t1\n\t\t<\/td>\n<td>\n\t\t\tRequests <a href=\"https:\/\/redfin.com\/CA\/San-Francisco\/830-El-Camino-Del-Mar-94121\/home\/604622\" target=\"_new\" rel=\"noopener noreferrer\">https:\/\/redfin.com\/blog\/&#8230;\/home\/604622<\/a>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t2\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tPasses request to server\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t3\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tReturns HTML including an ESI like <em>&lt;esi:include src=&#8221;\/similars?property_id=604622&#8243; \/&gt;<\/em>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t4\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tLookup \/similars?property_id=604622 in cache\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t5\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tCache lookup fails\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t6\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tMakes request to <em>\/similars?property_id=604622<\/em>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t7\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tReturns HTML for AJAX for Similars (e.g. a &lt;script&gt; block with a reference to <em>https:\/\/redfin.com\/blog\/extranet-similars?property_id=604622<\/em>)<br \/>\n\t\t\tResponse includes &#8220;no cache&#8221; headers\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t8\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tInjects the &lt;script&gt; block into the HTML to be returned<br \/>\n\t\t\tDoes NOT cache the server response\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t9\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tReturns HTML to Browser\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t10\n\t\t<\/td>\n<td>\n\t\t\tDisplays HTML\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t11\n\t\t<\/td>\n<td>\n\t\t\tExecutes &lt;script&gt; block\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t12\n\t\t<\/td>\n<td>\n\t\t\tRequests <em>https:\/\/redfin.com\/blog\/extranet-similars?property_id=604622<\/em>, including a special header saying &#8220;gimme the real content&#8221;\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t13\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tPasses <em>\/extranet-similars?property_id=604622<\/em> request to server\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t14\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tReturns HTML including an ESI like <em>&lt;esi:include src=&#8221;\/similars?property_id=604622&#8243; \/&gt;<\/em>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t15\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tLookup <em>\/similars?property_id=604622<\/em> in cache\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t16\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tCache lookup fails\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t17\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tMakes request to <em>\/similars?property_id=604622<\/em>, passing along special &#8220;gimme the real content&#8221; header\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t18\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tExamines request, sees special &#8220;gimme the real content&#8221; header\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t19\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tCalculates correct HTML to display Similar Listings and Similar Sales\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t20\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tReturns HTML including &#8220;please cache this&#8221; headers\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t21\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tInjects the Similars block into the HTML to be returned<br \/>\n\t\t\tDOES cache the server response\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t22\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tReturns HTML to Browser\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t23\n\t\t<\/td>\n<td>\n\t\t\tClient side Javascript injects Similars HTML into page\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<\/table>\n<p>That&#8217;s all great, but we still haven&#8217;t used the cache!  The cache entry will get used for subsequent requests for the same page, like this:<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"4\">\n<tr bgcolor=\"#e7e7e3\">\n<th>\n\t\t\tStep\n\t\t<\/th>\n<th>\n\t\t\tBrowser\n\t\t<\/th>\n<th>\n\t\t\tVarnish\n\t\t<\/th>\n<th>\n\t\t\tBackend Server\n\t\t<\/th>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t1\n\t\t<\/td>\n<td>\n\t\t\tRequests <a href=\"https:\/\/redfin.com\/CA\/San-Francisco\/830-El-Camino-Del-Mar-94121\/home\/604622\" target=\"_new\" rel=\"noopener noreferrer\">https:\/\/redfin.com\/blog\/&#8230;\/home\/604622<\/a>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t2\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tPasses request to server\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t3\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tReturns HTML including an ESI like <em>&lt;esi:include src=&#8221;\/similars?property_id=604622&#8243; \/&gt;<\/em>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t4\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tLookup <em>\/similars?property_id=604622<\/em> in cache\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t5\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tCache lookup SUCCEEDS\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t6\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tInjects the Similars block into the HTML to be returned\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr bgcolor=\"#f7f7f3\">\n<td>\n\t\t\t7\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t\tReturns HTML to Browser\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<tr>\n<td>\n\t\t\t8\n\t\t<\/td>\n<td>\n\t\t\tDisplays HTML including Similars (no AJAX calls)\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<td>\n\t\t<\/td>\n<\/tr>\n<\/table>\n<p>There are two things worth noting about this exchange.<\/p>\n<p><strong>First<\/strong>, when the backend server gets a request for <em>\/similars?property_id=604622<\/em>, it has to decide if it should be returning the real HTML, or should be returning Javascript that will retrieve the HTML via AJAX.  It makes this decision based on the value of a header passed in by the client.  When the client is making an AJAX request, it knows it better NOT get back a response that generates AJAX requests (that&#8217;d be a death spiral.)  Therefore, when it makes the AJAX request, it includes the special header.  In all other cases, the special header is NOT included.  When the header is included in a request, the server will generate the real HTML.  When the header is not included, Varnish may answer the request from cache, or it may pass through to the backend server.  If the request is fulfilled by the Varnish cache, then it&#8217;s the real HTML, but if it&#8217;s fulfilled by the backend server, it&#8217;ll be the AJAXy HTML.<\/p>\n<p><strong>Second<\/strong>, there are two URLs that have to do with similars.<\/p>\n<p><em>\/similars?property_id=604622<\/em> is an internal-use-only URL that returns the content (either the proper HTML or the AJAX code.)<\/p>\n<p><em>\/extranet-similars?property_id=604622<\/em> is an externally facing URL that only returns an ESI fragment (which will subsequently be filled in by Varnish.  This way, the ESI endpoints are never available to the extranet; Varnish can get to them, but extranet clients have no need for them.  This lets us be lazy with the ESI URLs.  For example, URLs that are exposed to the extranet do extra validation to check if the user is logged in, etc.  URLs for internal use only, such as the ESI URLs, can skip that work.  This also lets us change the URLs when the property changes, to facilitate cache busting (see the &#8220;Cache busting&#8221; section in <a href=\"https:\/\/redfin.com\/blog\/devblog\/2010\/05\/esi_and_caching_trickery_in_varnish.html\" target=\"_new\" rel=\"noopener noreferrer\">ESI and Caching Trickery in Varnish<\/a> for more information.<\/p>\n<p><strong>Pseudocode<\/strong><\/p>\n<p>OK, so we know what we want the interaction to look like.  What code will make this happen?  Here&#8217;s some Javaish pseudocode that illustrates how it might work:<\/p>\n<p><code><br \/>\n\/*<br \/>\nInvoked for requests like https:\/\/redfin.com\/blog\/[address]\/home\/[property id]<br \/>\n*\/<br \/>\npublic void handlePropertyRequest(Request request, Response response, long propId) {<br \/>\n&nbsp;&nbsp;&nbsp;Property property = getProperty(propId);<br \/>\n&nbsp;&nbsp;&nbsp;response.write(\"<em>&lt;html&gt;&lt;head&gt;&lt;\/head&gt;&lt;body&gt;<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>&lt;esi:include src='\/extranet-similars?property_id=<\/em>&quot; +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;propId +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;<em>&amp;last_mod=<\/em>&quot; +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.getLastModified() +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>'\/&gt;<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>&lt;\/body&gt;&lt;\/html&gt;<\/em>\");<br \/>\n}<br \/>\n<\/code><\/p>\n<p><code><br \/>\n\/*<br \/>\nInvoked for (extranet) requests like \/extranet-similars?property_id=[property id]&amp;last_mod=[date]<br \/>\n*\/<br \/>\npublic void handleExtranetSimilarsRequest(Request request, Response response, long propId) {<br \/>\n&nbsp;&nbsp;&nbsp;Property property = getProperty(propertyId);<br \/>\n&nbsp;&nbsp;&nbsp;response.write(\"<em>&lt;esi:include src='\/extranet-similars?property_id=<\/em>&quot; +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;propId +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;<em>&amp;last_mod=<\/em>&quot; +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.getLastModified() +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>'\/&gt;<\/em>\");<br \/>\n}<br \/>\n<\/code><\/p>\n<p><code><br \/>\n\/*<br \/>\nInvoked for (intranet) requests like \/similars?property_id=[property id]&amp;last_mod=[date]<br \/>\n*\/<br \/>\npublic void handleSimilarsRequest(Request request, Response response, long propId) {<br \/>\n&nbsp;&nbsp;&nbsp;if (null == request.getHeader(\"full_html\")) {<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/This request does NOT demand that we return the actual HTML.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/&nbsp;We will return a script block that will fetch the HTML via AJAX.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.write(\"<em>&lt;script&gt;<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>dojo.addOnLoad(<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>function() {<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>dojo.xhrGet({<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>url: 'https:\/\/redfin.com\/blog\/extranet-similars?property_id=<\/em>\" + propId + \"<em>',<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>load: function(response, ioArgs){<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>dojo.byId('similar_homes').innerHTML = response;<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>return response;<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>},<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>headers: {'full_html': 'true'},<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>handleAs: 'text'<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>});<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>}<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>);<\/em>\" +<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"<em>&lt;\/script&gt;<\/em>\");<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/Do NOT cache the script<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.setCacheable(false);<br \/>\n&nbsp;&nbsp;&nbsp;}<br \/>\n&nbsp;&nbsp;&nbsp;else {<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/This request wants the actual HTML for similars<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.write(getSimilarsHTML(propId));<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/The similars HTML is cacheable- that's the whole point!<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.setCacheable(true);<br \/>\n&nbsp;&nbsp;&nbsp;}<br \/>\n}<br \/>\n<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>When your webapp is serving up content that&#8217;s expensive to generate, you may want to serve it up asynchronously- via AJAX calls. This is particularly appealing when content is &#8220;below the fold.&#8221; However when that content is cached, you want to serve it up as quickly as possible. If you&#8217;ve already calculated the content, you&#8217;d [&hellip;]<\/p>\n","protected":false},"author":13401,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[57],"tags":[],"dashboard":[],"coauthors":[],"class_list":["post-41507","post","type-post","status-publish","format-standard","hentry","category-company-news"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.7 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Synchronous\/Asynchronous Switching with Varnish - Redfin Real Estate News<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Synchronous\/Asynchronous Switching with Varnish\" \/>\n<meta property=\"og:description\" content=\"When your webapp is serving up content that&#8217;s expensive to generate, you may want to serve it up asynchronously- via AJAX calls. This is particularly appealing when content is &#8220;below the fold.&#8221; However when that content is cached, you want to serve it up as quickly as possible. If you&#8217;ve already calculated the content, you&#8217;d [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/\" \/>\n<meta property=\"og:site_name\" content=\"Redfin Real Estate News\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/redfin\" \/>\n<meta property=\"article:published_time\" content=\"2010-05-07T21:55:36+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-10-05T20:12:36+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/b\/bb\/Alexander_cuts_the_Gordian_Knot.jpg\" \/>\n<meta name=\"author\" content=\"Michael Smedberg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@redfin\" \/>\n<meta name=\"twitter:site\" content=\"@redfin\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Michael Smedberg\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/\"},\"author\":{\"name\":\"Michael Smedberg\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#\\\/schema\\\/person\\\/1ec44a1785738a92423e0392733cbd87\"},\"headline\":\"Synchronous\\\/Asynchronous Switching with Varnish\",\"datePublished\":\"2010-05-07T21:55:36+00:00\",\"dateModified\":\"2020-10-05T20:12:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/\"},\"wordCount\":938,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/upload.wikimedia.org\\\/wikipedia\\\/commons\\\/b\\\/bb\\\/Alexander_cuts_the_Gordian_Knot.jpg\",\"articleSection\":[\"Company News\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/#respond\"]}],\"copyrightYear\":\"2010\",\"copyrightHolder\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/\",\"url\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/\",\"name\":\"Synchronous\\\/Asynchronous Switching with Varnish - Redfin Real Estate News\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/upload.wikimedia.org\\\/wikipedia\\\/commons\\\/b\\\/bb\\\/Alexander_cuts_the_Gordian_Knot.jpg\",\"datePublished\":\"2010-05-07T21:55:36+00:00\",\"dateModified\":\"2020-10-05T20:12:36+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/#primaryimage\",\"url\":\"http:\\\/\\\/upload.wikimedia.org\\\/wikipedia\\\/commons\\\/b\\\/bb\\\/Alexander_cuts_the_Gordian_Knot.jpg\",\"contentUrl\":\"http:\\\/\\\/upload.wikimedia.org\\\/wikipedia\\\/commons\\\/b\\\/bb\\\/Alexander_cuts_the_Gordian_Knot.jpg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/synchronousasynchronous_switching_with_varnish\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.redfin.com/news\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Synchronous\\\/Asynchronous Switching with Varnish\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#website\",\"url\":\"https:\\\/\\\/www.redfin.com/news\\\/\",\"name\":\"Redfin Real Estate News\",\"description\":\"The latest real estate news and research from technology-powered residential real estate company, Redfin.\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.redfin.com/news\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#organization\",\"name\":\"Redfin\",\"url\":\"https:\\\/\\\/www.redfin.com/news\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.redfin.com\\\/news\\\/wp-content\\\/uploads\\\/2020\\\/10\\\/Redfin-News-Logo.png\",\"contentUrl\":\"https:\\\/\\\/www.redfin.com\\\/news\\\/wp-content\\\/uploads\\\/2020\\\/10\\\/Redfin-News-Logo.png\",\"width\":1100,\"height\":235,\"caption\":\"Redfin\"},\"image\":{\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/redfin\",\"https:\\\/\\\/x.com\\\/redfin\",\"https:\\\/\\\/www.instagram.com\\\/redfinrealestate\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/redfin\",\"https:\\\/\\\/www.pinterest.com\\\/redfin\\\/\",\"https:\\\/\\\/en.wikipedia.org\\\/wiki\\\/Redfin\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/#\\\/schema\\\/person\\\/1ec44a1785738a92423e0392733cbd87\",\"name\":\"Michael Smedberg\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.redfin.com/news\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/Redfin-2025-Logo-B-150x150.jpgb98d1f204d143aab6d4240c534a1657e\",\"url\":\"https:\\\/\\\/www.redfin.com/news\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/Redfin-2025-Logo-B-150x150.jpg\",\"contentUrl\":\"https:\\\/\\\/www.redfin.com/news\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/Redfin-2025-Logo-B-150x150.jpg\",\"caption\":\"Michael Smedberg\"},\"url\":\"https:\\\/\\\/www.redfin.com/news\\\/author\\\/michael-smedbergredfin-com\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Synchronous\/Asynchronous Switching with Varnish - Redfin Real Estate News","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/","og_locale":"en_US","og_type":"article","og_title":"Synchronous\/Asynchronous Switching with Varnish","og_description":"When your webapp is serving up content that&#8217;s expensive to generate, you may want to serve it up asynchronously- via AJAX calls. This is particularly appealing when content is &#8220;below the fold.&#8221; However when that content is cached, you want to serve it up as quickly as possible. If you&#8217;ve already calculated the content, you&#8217;d [&hellip;]","og_url":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/","og_site_name":"Redfin Real Estate News","article_publisher":"https:\/\/www.facebook.com\/redfin","article_published_time":"2010-05-07T21:55:36+00:00","article_modified_time":"2020-10-05T20:12:36+00:00","og_image":[{"url":"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/b\/bb\/Alexander_cuts_the_Gordian_Knot.jpg","type":"","width":"","height":""}],"author":"Michael Smedberg","twitter_card":"summary_large_image","twitter_creator":"@redfin","twitter_site":"@redfin","twitter_misc":{"Written by":"Michael Smedberg","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/#article","isPartOf":{"@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/"},"author":{"name":"Michael Smedberg","@id":"https:\/\/www.redfin.com\/news\/#\/schema\/person\/1ec44a1785738a92423e0392733cbd87"},"headline":"Synchronous\/Asynchronous Switching with Varnish","datePublished":"2010-05-07T21:55:36+00:00","dateModified":"2020-10-05T20:12:36+00:00","mainEntityOfPage":{"@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/"},"wordCount":938,"commentCount":0,"publisher":{"@id":"https:\/\/www.redfin.com\/news\/#organization"},"image":{"@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/#primaryimage"},"thumbnailUrl":"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/b\/bb\/Alexander_cuts_the_Gordian_Knot.jpg","articleSection":["Company News"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/#respond"]}],"copyrightYear":"2010","copyrightHolder":{"@id":"https:\/\/www.redfin.com\/news\/#organization"}},{"@type":"WebPage","@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/","url":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/","name":"Synchronous\/Asynchronous Switching with Varnish - Redfin Real Estate News","isPartOf":{"@id":"https:\/\/www.redfin.com\/news\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/#primaryimage"},"image":{"@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/#primaryimage"},"thumbnailUrl":"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/b\/bb\/Alexander_cuts_the_Gordian_Knot.jpg","datePublished":"2010-05-07T21:55:36+00:00","dateModified":"2020-10-05T20:12:36+00:00","breadcrumb":{"@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/#primaryimage","url":"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/b\/bb\/Alexander_cuts_the_Gordian_Knot.jpg","contentUrl":"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/b\/bb\/Alexander_cuts_the_Gordian_Knot.jpg"},{"@type":"BreadcrumbList","@id":"https:\/\/www.redfin.com\/news\/synchronousasynchronous_switching_with_varnish\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.redfin.com\/news\/"},{"@type":"ListItem","position":2,"name":"Synchronous\/Asynchronous Switching with Varnish"}]},{"@type":"WebSite","@id":"https:\/\/www.redfin.com\/news\/#website","url":"https:\/\/www.redfin.com\/news\/","name":"Redfin Real Estate News","description":"The latest real estate news and research from technology-powered residential real estate company, Redfin.","publisher":{"@id":"https:\/\/www.redfin.com\/news\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.redfin.com\/news\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.redfin.com\/news\/#organization","name":"Redfin","url":"https:\/\/www.redfin.com\/news\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.redfin.com\/news\/#\/schema\/logo\/image\/","url":"https:\/\/www.redfin.com\/news\/wp-content\/uploads\/2020\/10\/Redfin-News-Logo.png","contentUrl":"https:\/\/www.redfin.com\/news\/wp-content\/uploads\/2020\/10\/Redfin-News-Logo.png","width":1100,"height":235,"caption":"Redfin"},"image":{"@id":"https:\/\/www.redfin.com\/news\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/redfin","https:\/\/x.com\/redfin","https:\/\/www.instagram.com\/redfinrealestate\/","https:\/\/www.linkedin.com\/company\/redfin","https:\/\/www.pinterest.com\/redfin\/","https:\/\/en.wikipedia.org\/wiki\/Redfin"]},{"@type":"Person","@id":"https:\/\/www.redfin.com\/news\/#\/schema\/person\/1ec44a1785738a92423e0392733cbd87","name":"Michael Smedberg","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.redfin.com\/news\/wp-content\/uploads\/2025\/06\/Redfin-2025-Logo-B-150x150.jpgb98d1f204d143aab6d4240c534a1657e","url":"https:\/\/www.redfin.com\/news\/wp-content\/uploads\/2025\/06\/Redfin-2025-Logo-B-150x150.jpg","contentUrl":"https:\/\/www.redfin.com\/news\/wp-content\/uploads\/2025\/06\/Redfin-2025-Logo-B-150x150.jpg","caption":"Michael Smedberg"},"url":"https:\/\/www.redfin.com\/news\/author\/michael-smedbergredfin-com\/"}]}},"_links":{"self":[{"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/posts\/41507","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/users\/13401"}],"replies":[{"embeddable":true,"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/comments?post=41507"}],"version-history":[{"count":0,"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/posts\/41507\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/media?parent=41507"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/categories?post=41507"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/tags?post=41507"},{"taxonomy":"dashboard","embeddable":true,"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/dashboard?post=41507"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.redfin.com\/news\/wp-json\/wp\/v2\/coauthors?post=41507"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}