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 headers in API Mesh
After adding VCL snippets in the Fastly Setup, your Commerce GraphQL URL is now in the following format: <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
The following sections describe how to configure Fastly in Adobe Commerce.
Add VCL snippets
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.
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 = 30s;.connect_timeout = 30s;.dynamic = true;.first_byte_timeout = 15s;.host = "edge-graph.adobe.io";.host_header = "edge-graph.adobe.io";.keepalive_time = 25s;.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";.max_tls_version = "1.3";.min_tls_version = "1.3";.probe = {.dummy = true;.initial = 5;.request = "HEAD / HTTP/1.1" "Host: edge-graph.adobe.io" "Connection: close";.threshold = 1;.timeout = 2s;.window = 5;}}
Enables the bypass header in API Mesh:
Name - api_mesh_recv
Type - recv
Priority - 10
Content:
Copied to your clipboard# set mesh backend for /api/ requestsif (req.url ~ "^/api/") {set req.backend = F_edge_graph_adobe_io;}if (req.http.x-commerce-bypass-fastly-cache == "true") {return (pass);}# Determines what GraphQL can be cachedif ((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 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);}Name - keep-alive-vcl-miss
Type - miss
Priority - 100
Content:
Copied to your clipboardset bereq.http.Connection = "keep-alive";
Name - keep-alive-vcl-pass
Type - pass
Priority - 100
Content:
Copied to your clipboardset bereq.http.Connection = "keep-alive";
In Fastly Configuration click Upload VCL to Fastly. Click Save Config.
Configure Fastly Next-Gen WAF
If you are using Adobe Commerce with Fastly Next-Gen WAF enabled, you must add the following VCL snippet, which prevents the WAF from inspecting the request twice. If you do not add this snippet, the Next-Gen WAF strips headers from the request, which can cause errors.
Name - api_mesh_inspection
Type - recv
Priority - 1
Content:
Copied to your clipboardif (table.lookup(eds_domains, req.http.Host) && req.url ~ "/graphql"){set req.http.x-sigsci-no-inspection = "disabled";}
Configure default backend
The default backend does not handle "/api/" requests. To allow API requests, add a condition to the existing backend:
In Fastly Configuration > Backend Settings, click on the gear icon next to <project_id>.magento.cloud.
Click Create a new request condition and add a condition like the following example:
Name - default_backend
Apply if...:
Copied to your clipboardreq.url !~ "^/api/"
Click Create on the condition.
Click Create on the backend.
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, 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, HIT, MISSx-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.