December 14, 2021
4 min read time

Two-Minute Tech Tuesdays - Synthetic Responses

In this week’s Two Minute Tech Tuesday, we'll talk about synthetic responses. These are responses that didn't originate from a backend server and there were synthetically generated by Varnish.

 

 

Before we dive into synthetic responses, we need to take out the synthetic part from the equation and talk about regular responses and how they get composed in Varnish. Here's a standard interaction that involves Varnish:

  1. The client sends a request
  2. Varnish doesn't have the response stored in cache but fetches it from the origin through a backend fetch
  3. The origin responds
  4. The object gets stored in the cache
  5. Varnish delivers it to the client.

ezgif.com-gif-maker

 

Upon the next request, Varnish does have the object stored in the cache and can deliver it immediately. Let's take the backend fetch out of the equation and compute the result ourselves.

  1. The request gets received by Varnish
  2. Varnish composes the output
  3. Varnish returns it directly

That's basically what a synthetic response is — a response that didn't originate from a backend server. These synthetic responses already appear behind the scenes in the built-in VCL.

When you send a request using the "PRI" request method, Varnish will respond with a "405 Method Not Allowed" error. When you send a request without a "Host" header, you'll get a "Bad Request" 400 synthetic response. Here's the HTML output that gets generated when these synthetic errors are triggered:

 

 

As you've seen in the built-in VCL code, synthetic responses are triggered through a "return(synth())" statement:

return(synth(405));

It requires a status code, but you can also add add a custom response reason. When you call "return(synth))", you transition in the VCL finite state machine into the "vcl_synth" subroutine that prepares the output. 

It uses this HTML output template and injects the "resp.status" and "resp.reason" variables.

 

 

So, the first argument of "synth()" constitutes the "resp.status" and the second one, which is a string, is the "resp.reason".

Let's take it to the next level with this example, where an API gets accelerated by Varnish and the "/me" endpoint results in a synthetic response.


 

  1. This response contains a JSON object that has a "name" property who's value gets populated by a "name" cookie. If that cookie is set, it uses the name. Otherwise, it uses "anonymous".
  2. In "vcl_synth" we modify the output template by setting the content type to "application/json" and replacing the entire HTML template with the raw input that comes from "resp.reason".
  3. When we call the "/me" endpoint without the cookie, the "name" property has the value "anonymous". When we do use a cookie, and have the value of the name, for example, Thijs, the "name" property is "Thijs".

Synthetic responses are a really powerful mechanism to return error messages from Varnish. Also to offload the origin server and execute simple, really narrowly scoped application logic on the edge.

Varnish is an excellent edge computing platform and it allows you to interact with third-party systems over an HTTP interface, but it can also interact with databases or with key-value stores. There's even an enterprise module that allows you to cache these synthetic responses so they don't have to be computed upon every single request.


varnish_6_by_example_download