Dynamic cache control with Fastly
Adding a content delivery network (CDN) for caching dynamic content with API Mesh for Adobe Developer App Builder provides additional security and improved performance. Follow these instructions to integrate API Mesh, Adobe Commerce, and Fastly (provided with Adobe Commerce Pro accounts).
Configure Fastly for edge meshes
There are two requirements for using edge meshes with Fastly:
- You must set your TLS minimum and maximum versions to TLS
1.3
. - You must add the following custom VCL to configure Fastly as a backend:
Custom VCL in Fastly
The following VCL points the Fastly backend to edge-graph.adobe.io
which corresponds to the Production
workspace in your project.
Copied to your clipboard# Backend declarationbackend F_edge_graph_adobe_io {.always_use_host_header = true;.between_bytes_timeout = 10s;.connect_timeout = 1s;.dynamic = true;.first_byte_timeout = 15s;.host = "edge-graph.adobe.io";.host_header = "edge-graph.adobe.io";.max_connections = 200;.port = "443";.share_key = "XXXXXXXXXXXXXXXX";.ssl = true;.ssl_cert_hostname = "edge-graph.adobe.io";.ssl_check_cert = always;.ssl_sni_hostname = "edge-graph.adobe.io";.probe = {.dummy = true;.initial = 5;.request = "HEAD / HTTP/1.1" "Host: edge-graph.adobe.io" "Connection: close";.threshold = 1;.timeout = 2s;.window = 5;}}# Subroutinesub vcl_recv {if (req.url ~ "^/api/") {set req.backend = F_edge_graph_adobe_io;}}
Custom VCL in Adobe Commerce
For more information on the configuration process, see Configure Fastly in Adobe Commerce.
- Name - api_mesh_backend
- Type - init
- Priority - 1
- Content:
Copied to your clipboard# Backend declarationbackend F_edge_graph_adobe_io {.always_use_host_header = true;.between_bytes_timeout = 10s;.connect_timeout = 1s;.dynamic = true;.first_byte_timeout = 15s;.host = "edge-graph.adobe.io";.host_header = "edge-graph.adobe.io";.max_connections = 200;.port = "443";.share_key = "XXXXXXXXXXXXXXXX";.ssl = true;.ssl_cert_hostname = "edge-graph.adobe.io";.ssl_check_cert = always;.ssl_sni_hostname = "edge-graph.adobe.io";.probe = {.dummy = true;.initial = 5;.request = "HEAD / HTTP/1.1" "Host: edge-graph.adobe.io" "Connection: close";.threshold = 1;.timeout = 2s;.window = 5;}}# Subroutinesub vcl_recv {if (req.url ~ "^/api/") {set req.backend = F_edge_graph_adobe_io;}}
Configure headers in API Mesh
After adding VCL snippets in the Fastly Setup, your Commerce GraphQL URL is now in the following format with no api_key
appended: <Commerce-URL>/api/<meshId>/graphql
To distinguish between requests from users and requests from API Mesh, use the following source operation header to prevent Fastly from caching headers that come directly from API Mesh:
Copied to your clipboard"x-commerce-bypass-fastly-cache": "true"
When bypassing the cache, you must also specify which headers should be preserved in the responseConfig
:
Copied to your clipboard"responseConfig": {"headers": ["x-magento-cache-id","x-magento-tags","set-cookie","pragma","cache-control","expires","x-content-type-options","x-xss-protection","x-platform-server"]}
Using Fastly also requires all queries to be GET
queries. POST
queries are not cached. To enforce this in your mesh, add the following configuration option:
"useGETForQueries": true
Use the fastly-debug:1
request header to get more information from Fastly on each request. Adobe does not recommend using debug headers in production environments.
Fastly example mesh
The following example mesh specifies the headers to cache, enables the cache bypass, and sets all queries to pass as GET
queries.
Copied to your clipboard{"meshConfig": {"responseConfig": {"includeHTTPDetails": true},"sources": [{"name": "Core","handler": {"graphql": {"endpoint": "https://venia.magento.com/graphql","operationHeaders": {"x-magento-cache-id": "{context.headers['x-magento-cache-id']}","Store": "{context.headers['store']}" ,"Authorization": "{context.headers['authorization']}","Content-Type": "application/json","x-commerce-bypass-fastly-cache": "true"},"useGETForQueries": true}},"responseConfig": {"headers": ["x-magento-cache-id","x-cache","x-magento-tags","set-cookie","pragma","cache-control","expires","x-content-type-options","x-xss-protection","x-platform-server"]}}]}}
Cache header prefixing
API Mesh prefixes any Fastly source headers with their source name. For example, a source named "commerce" with an x-magento-cache-id
header is converted to x-commerce-magento-cache-id
. However, if your endpoint URL contains "magento", API Mesh assumes you are connecting to an Adobe Commerce instance and does not prefix your headers with a source name. Using the previous example, your header would remain x-magento-cache-id
.
Test your mesh
After you create or update your mesh, run an aio api-mesh:describe
command to view your mesh URL. Run a query against this URL to confirm that your mesh is working correctly.
Configure Fastly in Adobe Commerce
After setting up your API Mesh, open your Adobe Commerce Admin and use the following steps to configure dynamic content caching with the provided Fastly CDN. You will need access to the following prerequisites:
- Adobe Commerce
- Admin access
- API Mesh
- The ability to create or update a mesh
Get the following Fastly credentials:
- Fastly Service ID
- Fastly API Token
In the Adobe Commerce Admin, select Store > Settings > Configuration > Advanced > System > Full Page Cache and set the Caching Application field to Fastly CDN.
Enter the Fastly credentials you retrieved previously into the Fastly Service ID and Fastly API Token fields. Then click the Test Credentials button to verify that your credentials are correct.
Under Fastly Configuration > Custom VCL Snippets click Create and add the following snippets. For more information on VCL subroutines, see Custom Subroutines.
NOTE: The
Priority
of each VCL snippet determines the order in which VCL subroutines are executed. The followingPriority
fields only apply to the default configuration of Adobe Commerce. If you have other custom snippets, you will need to adjust the priorities accordingly.Allows API Mesh to function as a Fastly backend. If you added this VCL as part of Configure Fastly for edge meshes, you do not need to add it again.
Name - api_mesh_backend
Type - init
Priority - 1
Content:
Copied to your clipboard# Backend declarationbackend F_edge_graph_adobe_io {.always_use_host_header = true;.between_bytes_timeout = 10s;.connect_timeout = 1s;.dynamic = true;.first_byte_timeout = 15s;.host = "edge-graph.adobe.io";.host_header = "edge-graph.adobe.io";.max_connections = 200;.port = "443";.share_key = "XXXXXXXXXXXXXXXX";.ssl = true;.ssl_cert_hostname = "edge-graph.adobe.io";.ssl_check_cert = always;.ssl_sni_hostname = "edge-graph.adobe.io";.probe = {.dummy = true;.initial = 5;.request = "HEAD / HTTP/1.1" "Host: edge-graph.adobe.io" "Connection: close";.threshold = 1;.timeout = 2s;.window = 5;}}# Subroutinesub vcl_recv {if (req.url ~ "^/api/") {set req.backend = F_edge_graph_adobe_io;}}
Enables the bypass header in API Mesh:
Name - api_mesh_recv
Type - recv
Priority - 10
Content:
Copied to your clipboardif (req.http.x-commerce-bypass-fastly-cache == "true") {return (pass);}
Determines what GraphQL can be cached:
Name - api_mesh_recv2
Type - recv
Priority - 60
Content:
Copied to your clipboardif ((req.request == "GET" || req.request == "HEAD") && (req.url.path~"/graphql" || req.url "^/api/(.*)") && req.url.qs~"query=") {set req.http.graphql = "1";}else {unset req.http.graphql;}if (req.url.path !~ "/graphql" && req.url !~ "^/api/(.*)") {set req.http.Magento-Original-URL = req.url;set req.url = querystring.regfilter(req.url, "^(utm_.*|gclid|gdftrk|_ga|mc_.*|trk_.*|dm_i|_ke|sc_.*|fbclid)$");}
Cache miss - replace the
<mesh_id>
and<mesh_api_key>
placeholders with the information from your API Mesh URL, which has the following structure:https://graph.adobe.io/api/<meshId>/graphql?api_key=<your_apiKey>
. You can retrieve this information by running anaio api-mesh:describe
command:Name - api_mesh_miss
Type - miss
Priority - 60
Content:
Copied to your clipboardif (req.url ~ "^/api/") {set req.backend = F_graph_prod_adobe_io;}//API Mesh prod mappingif (req.url ~ "^/api/<mesh_id>") {set bereq.http.x-api-key = "<mesh_api_key>";}# //Optionally add another mesh# //API Mesh stage mapping# if (req.url ~ "^/api/<mesh_id>") {# set bereq.http.x-api-key = "<mesh_api_key>";# }
The following
api_mesh_pass
snippet allows you to query your mesh URL without appending theapi_key
:Cache pass - replace the
<mesh_id>
and<mesh_api_key>
placeholders with the information from your mesh URL, which has the following structure:https://graph.adobe.io/api/<meshId>/graphql?api_key=<mesh_api_key>
:Name - api_mesh_pass
Type - pass
Priority - 10
Content:
Copied to your clipboardif (req.url ~ "^/api/") {set req.backend = F_graph_prod_adobe_io;}//API Mesh prod mappingif (req.url ~ "^/api/<mesh_id>") {set bereq.http.x-api-key = "<mesh_api_key>";}# //Optionally add another environment# //API Mesh stage mapping# if (req.url ~ "^/api/<mesh_id>") {# set bereq.http.x-api-key = "<mesh_api_key>";# }
Cache fetch:
Name - api_mesh_fetch
Type - fetch
Priority - 10
Content:
Copied to your clipboardif (req.http.x-commerce-bypass-fastly-cache == "true") {return (pass);}
Cache deliver:
Name - api_mesh_deliver
Type - deliver
Priority - 10
Content:
Copied to your clipboardif (req.http.x-commerce-bypass-fastly-cache == "true") {return (deliver);}
In Fastly Configuration > Backend Settings click Create. Add a new backend with the following information:
- Condition -
req.url ~ "^/api/(.*)" ,
- Address - graph.adobe.io
- Priority - 8
- Condition -
In Fastly Configuration click Upload VCL to Fastly. Click Save Config.
Test your configuration
Run the following cURL command, replacing <Commerce-URL>
and <Magento-Cache-Id>
with your Adobe Commerce storefront values.
Copied to your clipboardcurl --globoff --include '<Commerce-URL>/api/<meshId>/graphql?query={products(search%3A%20%22c%22){items{sku}}}' --header 'x-magento-cache-id: <Magento-Cache-Id>' --header 'Fastly-Debug: 1' -w "\n\ntime_starttransfer: %{time_starttransfer}\n"
Review the values of the x-cache
and x-cache-hits
headers to determine if the cache is being used. The first time you run this query, the headers should return:
Copied to your clipboardx-cache: MISS, MISSx-cache-hits: 0
Two MISS
values and 0
hits indicate that the cache was not used in this query. Run the cURL command again and you should see the values change to the following:
Copied to your clipboardx-cache: MISS, HITx-cache-hits: 1
A value of MISS, HIT
and 1
or more hits indicates that the cache is in use. You can also verify cache usage by comparing cached and uncached response times.