System Information
- Strapi Version: 5.4.2
- Operating System: macOS Sequoia 15.1
- Database: SQLite
- Node Version: 20.17.0
- NPM Version: 10.8.2
Hello everyone!
tl;dr:
- How to track changes from the previous version of a field value, to run operations after it has changed (API call, updating other fields, etc.)?
- potential bug: events other than FindOne do not seem to fire from the Strapi middleware.
ONE:
I have a collection type projects
. I am trying to listen for changes to the location
property, and if it has changed, fetch data from an API to update property country
. I have been able to do this in @/src/api/project/content-types/project/lifecycles.ts
, with a beforeUpdate
hook.
The problem: the hook runs on the change of any project property, and I am unable to track whether specifically location
has changed. The value of location
remains the same in beforeUpdate
and afterUpdate
hooks, and also with polling strapi using await strapi.documents(...).findOne(...)
inside either of the hooks.
import axios from "axios";
const getCountryFromCoordinates = async ({ lat, lng }) => {
// Placeholder logic for demo purposes
return "...";
};
export default {
async beforeUpdate(event) {
const { data } = event.params;
const ctx = strapi.requestContext.get();
const existingEntry = await strapi.documents("api::project.project").findOne({
documentId: event.params.where.documentId,
});
strapi.log.debug(
`beforeUpdate location from database: ${JSON.stringify(existingEntry?.location)}`
);
strapi.log.debug(
`beforeUpdate location from event data: ${JSON.stringify(data?.location)}`
);
strapi.log.debug(
`beforeUpdate location from request body: ${JSON.stringify(ctx.request.body?.location)}`
);
},
async afterUpdate(event) {
const { data } = event.params;
// Demo call to the country function
const country = await getCountryFromCoordinates({ lat: 0, lng: 0 });
strapi.log.debug(`afterUpdate demo country: ${country}`);
const ctx = strapi.requestContext.get();
const existingEntry = await strapi.documents("api::project.project").findOne({
documentId: event.params.where.documentId,
});
strapi.log.debug(
`afterUpdate location from database: ${JSON.stringify(existingEntry?.location)}`
);
strapi.log.debug(
`afterUpdate location from event data: ${JSON.stringify(data?.location)}`
);
strapi.log.debug(
`afterUpdate location from request body: ${JSON.stringify(ctx.request.body?.location)}`
);
},
};
TWO:
After reading further in the Strapi issues page, Lifecycle hooks can't access previous values of components · Issue #20346 · strapi/strapi · GitHub, I have also tried to achieve this by adding a middleware to index.ts
, which unfortunately only seems to register the findOne
event. This is different to the official Strapi documentation: Extending the Document Service behavior | Strapi 5 Documentation
console.log("Strapi is starting...");
export default {
register({ strapi }) {
console.log("Register function executed.");
strapi.log.error("Register function executed.");
strapi.documents.use((context, next) => {
const applyTo = ["api::project.project"];
// Only run for certain content types
if (!applyTo.includes(context.uid)) {
return next();
}
strapi.log.debug(`ACTION TYPE HIGH-LEVEL: ${context.action}`);
// Only run for update actions – this does not fire when I update a project! if it's set to FindOne, it fires OK.
if (["update"].includes(context.action)) {
const { documentId } = context.params;
strapi.log.debug(`🔵🔵 TYPE: ${context.action} action triggered.`);
strapi.log.debug(`🔵🔵 id: ${JSON.stringify(context.params.documentId)}`);
}
return next();
});
},
// bootstrap, destroy etc.
};
Any help is much appreciated!