Strapi4 policies: Can find body in policyContext | Throw Error in Policy

System Information
  • Strapi Version: 4.15
  • Operating System: Docker Node16 Alpine
  • Database: Postgres
  • Node Version: 16
  • NPM Version: 8.5.5

Hey together,

I’m writing a policy where I like to work with the body. As example: I like to check if the user filled their firstname and lastname, that they are not sending an empty string.

Also I have no idea how to send an error message. In Strapi3 there was a ctx object where I got access to this with ease.

This is my current code:

'use strict';

/**
 * `updateOwnerOnly` policy.
 */

module.exports = (policyContext, config, { strapi }) => {
    // Add your own logic here.
    strapi.log.info('updateOwnerOnly policy.');

    console.log(policyContext.req)

    if (policyContext.state.auth.strategy.name === "api-token") {
      if (policyContext.state.auth.credentials.type === "full-access")
        return true;
    } else if (
      policyContext.state.auth.strategy.name === "users-permissions"
    ) {
      // Skip for admins
      if (policyContext.state.auth.credentials.role.type === "admin")
        return true;

      const currentUserId = policyContext.state.auth.credentials.id;
      const userToUpdate = policyContext.params.id;

      // Unable that an user can update an other user
      if (currentUserId != userToUpdate) {
        strapi.log.info(`WARNING: User ${currentUserId} tried to edit user ${userToUpdate}`);
        throw new Error("Unable to edit this user ID");
      }
      return true
    }

    return false;
};

Everything works fine. I can check that the user only update his own profile and admins can do what they want. But unfortunately I can’t find any body information in policyContext and also when I throw a new Error the message in my API don’t get through. I found in the docs to use ctx.badRequest("My Error Message") but as I sad I don’t have an ctx object.

I hope someone can give me a hint or bring me on the right track.

Thanks in advance,
Lars

I were able to find the the body.
You can find the body elements so: policyContext.request.body

Unfortunately I still have no idea how to display an error message in the API

Okay I where able to figure it out by myself. Unfortunately there is no ctx.badRequest for policies. I added the PolicyError class from utils to my policy and then I where able to post custom error messages.

Here my final code:

'use strict';

/**
 * `updateOwnerOnly` policy.
 */

module.exports = (policyContext, config, { strapi }) => {
    const { PolicyError } = require("@strapi/utils").errors;
    // Add your own logic here.
    strapi.log.info('updateOwnerOnly policy.');

    if (policyContext.state.auth.strategy.name === "api-token") {
      if (policyContext.state.auth.credentials.type === "full-access")
        return true;
    } else if (
      policyContext.state.auth.strategy.name === "users-permissions"
    ) {
      // Skip for admins
      if (policyContext.state.auth.credentials.role.type === "admin")
        return true;

      const currentUserId = policyContext.state.auth.credentials.id;
      const userToUpdate = policyContext.params.id;

      // Unable that an user can update an other user
      if (currentUserId != userToUpdate) {
        strapi.log.info(`WARNING: User ${currentUserId} tried to edit user ${userToUpdate}`);
        throw new PolicyError('Unable to edit this user ID');
      }
      if (
        policyContext.request.body.lastname === undefined ||
        policyContext.request.body.lastname.trim() === ""
      )
        throw new PolicyError("Lastname name is required");
      if (
        policyContext.request.body.firstname === undefined ||
        policyContext.request.body.firstname.trim() === ""
      )
        throw new PolicyError("Firstname is required");
      return true
    }

    return false;
};

1 Like

Hey thanks for finding out you can throw a policy error. I noticed you can throw other errors from the utils too. Like I am using

const {  UnauthorizedError } = require("@strapi/utils").errors;

 throw new UnauthorizedError("Custom");

Which does give a 401 instead of a 403 HTTP status.