Open ViVa98 opened 3 years ago
Hi @ViVa98
The version of the middleware that you are using does not support anything like that, however @stafyniaksacha has been working on a v2 (you can check out the Beta branch, which contains a great amount of new features, including the ability to set custom routes, which might help you fix your issue !
You can try installing it by using npm install --save strapi-middleware-cache@2.0.1-beta.2
However note that this version's configuration is not backwards compatible with v1, so do take a look at the documentation on that branch to learn how to configure it.
Hope this helps !
@patrixr thanks for the reply and info about the beta version. There is an option to specify a particular API endpoint to bust when a PUT/DELETE request comes for the same endpoint.
What I'm looking for is to bust a specific endpoint cache when PUT/DELETE request for another endpoint.
Requesting @stafyniaksacha to please go through the above-mentioned use case and also to provide a brief/one-line description for the beta version.
Hello @ViVa98
You can use the internal cache middleware by setting the withStrapiMiddleware
to true
and use it in lifecycle methods
Let's say you have this cache config:
// file: config/cache.js
/**
* @type {import('strapi-middleware-cache').UserMiddlewareCacheConfig}
*/
module.exports = {
enabled: true,
clearRelatedCache: true,
withStrapiMiddleware: true,
models: [
{
model: "profile",
injectDefaultRoutes: false,
routes: [
"/profiles/:slug",
],
},
],
};
this will register only /profiles/:slug
route to be cached, you have to clear it manually then with lifecycles:
// file: api/profile/models/profile.js
/**
* Lifecycle callbacks for the `profile` model.
*/
async function clearProfileCache(data) {
const cache = strapi?.middleware?.cache || {};
if (cache && typeof cache.clearCache === "function") {
const profileCache = cache.getCacheConfig("profile");
if (profileCache && typeof data.slug === "string") {
await cache.clearCache(profileCache, { slug: data.slug });
return;
}
}
}
module.exports = {
lifecycles: {
async afterDelete(result, data) {
try {
await clearProfileCache(result);
} catch (error) {
strapi.log.error("profile afterDelete:clearProfileCache");
strapi.log.error(error);
if (
typeof strapi.plugins?.sentry?.services?.sentry?.sendError ===
"function"
) {
strapi.plugins.sentry.services.sentry.sendError(error);
}
}
},
async afterUpdate(result, params, data) {
try {
await clearProfileCache(result);
} catch (error) {
strapi.log.error("profile afterUpdate:clearProfileCache");
strapi.log.error(error);
if (
typeof strapi.plugins?.sentry?.services?.sentry?.sendError ===
"function"
) {
strapi.plugins.sentry.services.sentry.sendError(error);
}
}
},
},
};
[cache] GET /shops/shop_name **MISS**
GET /shops/shop_name (358 ms) 200
PUT /shops/id (867 ms) 200
[cache] GET /shops/shop_name **HIT**
GET /shops/shop_name (3 ms) 200
[cache] GET /profiles/username **MISS**
GET /profiles/username (280 ms) 200
PUT /profiles/id (1023 ms) 200
[cache] GET /profiles/username **MISS**
GET /profiles/username (324 ms) 200
And also for the shops
when logged shopCache
the paramNames array is empty []
instead of ['shop_name']
. But for profiles
, paramNames array is ['username']
Sorry, I don't understand what you are expecting. Can you provide more information of what you need and your current configuration?
paramNames
are populated from cache config (and not gathered from strapi),
on the example I sent there is only one route /profiles/:slug
registered with a slug
param on profile
collection
paramNames are populated from cache config (and not gathered from strapi), on the example I sent there is only one route /profiles/:slug registered with a slug param on profile collection
You're right about populating paramNames from the cache config but in my case, I configured two models with a route in each one.
// file: config/middleware.js
module.exports = ({ env }) => ({
settings: {
cache: {
enabled: true,
clearRelatedCache: true,
withStrapiMiddleware: true,
models: [
{
model: "profile",
injectDefaultRoutes: false,
routes: ["/profiles/:username"],
},
{
model: "shop",
injectDefaultRoutes: false,
routes: ["/shops/:shop_name"],
},
],
},
},
});
After the below line in file: api/shop/models/shop.js
const shopCache = cache.getCacheConfig("shop");
I tried logging shopCache
and the result is
{
singleType: false,
hitpass: [Function: hitpass],
injectDefaultRoutes: false,
headers: [],
maxAge: 3600000,
model: 'shop',
routes: [ { path: '/shops/:shop_name', method: 'GET', paramNames: [] } ]
}
If you observe paramNames
above, it is empty. It has to be filled like ['shop_name']
.
For some reason, paramNames
is not populating for my second model configured in file: config/middleware.js
. Tried hardcoding the shopCache variable like below instead of assigning from cache.getCacheConfig("shop")
const shopCache = {
singleType: false,
hitpass: [Function: hitpass],
injectDefaultRoutes: false,
headers: [],
maxAge: 3600000,
model: 'shop',
routes: [ { path: '/shops/:shop_name', method: 'GET', paramNames: ["shop_name"] } ]
}
After this modification cache is busting when PUT/DELETE request is completed. @stafyniaksacha thank you.
Hum, this is wired.
The paramNames
should be resolved here (with /:([^/]+)/g
regex)
And the model
entry should be shop
in this case (not link
)
Can you log the cache.options
In your file: api/shop/models/shop.js
?
So we can check the resolved configuration.
Also, we will have more information using debug
log level:
// file: config/middleware.js
module.exports = ({ env }) => ({
settings: {
logger: {
level: "debug",
exposeInContext: true,
},
cache: {
// ...
},
},
});
Response from the cache.options using basic console.log
{
type: 'mem',
logs: true,
enabled: true,
populateContext: false,
populateStrapiMiddleware: false,
enableEtagSupport: false,
enableXCacheHeaders: false,
clearRelatedCache: true,
withKoaContext: false,
withStrapiMiddleware: true,
headers: [],
max: 500,
maxAge: 3600000,
cacheTimeout: 500,
models: [
{
singleType: false,
hitpass: [Function: hitpass],
injectDefaultRoutes: false,
headers: [],
maxAge: 3600000,
model: 'profile',
routes: [Array]
},
{
singleType: false,
hitpass: [Function: hitpass],
injectDefaultRoutes: false,
headers: [],
maxAge: 3600000,
model: 'shop',
routes: [Array]
}
]
}
Response using strapi.log.debug
after adding logger to middleware file
{
"type":"mem",
"logs":true,
"enabled":true,
"populateContext":false,
"populateStrapiMiddleware":false,
"enableEtagSupport":false,
"enableXCacheHeaders":false,
"clearRelatedCache":true,
"withKoaContext":false,
"withStrapiMiddleware":true,
"headers":[],
"max":500,
"maxAge":3600000,
"cacheTimeout":500,
"models":[
{
"singleType":false,
"injectDefaultRoutes":false,
"headers":[],
"maxAge":3600000,
"model":"profile",
"routes":[
{
"path":"/profiles/:username",
"method":"GET",
"paramNames":["username"]
}
]
},
{
"singleType":false,
"injectDefaultRoutes":false,
"headers":[],
"maxAge":3600000,
"model":"shop",
"routes":[
{
"path":"/shops/:shop_name",
"method":"GET",
"paramNames":[]
}
]
}
]
}
I have a model with 3 fields containing {id(auto-generated), username, email}
I have modified the default GET endpoint to "username" instead of "id" to search specific record based on username like
GET /profiles/someusername
But for PUT/DELETE I'm using "id" as the endpoint
PUT/DELETE /profiles/random_generated_id
Whenever I use PUT/DELETE, data changes in the database, the previously cached data of different endpoint is not busting. I'm thinking of extending those PUT/DELETE API and manually deleting the specific endpoint's cache.
Help me get out of this situation.