Implement premium access to fields for api users

System Information
  • Strapi Version:
  • Operating System:
  • Database:
  • Node Version:
  • NPM Version:
  • Yarn Version:

I’m new to strapi and still struggling with mostly everything.

I have a collection type with following fields:

  • title
  • excerpt
  • content (component)
  • category (relation)
  • premium (boolean)

There are premium articles (for premium users) and public articles (for all users). But, I want non premium users to still have limited access to the articles: all fields except content.

I was able to implement this by writing 2 custom controllers: find and findOne.(/src/api/articles/controllers/articles.js). In the custom controller find I check ctx.query.populate and remove ‘content’ from it. (“content” is never needed on find)

In the custom findOne controller I check the user’s role. If the role is premium I just call return await super.findOne(ctx);. For non premium roles (authenticated or public) I make the same call, then check the premium field on the result. If this is true, I delete the content field from the result and then return said result:

if (!data.attributes.public) {
    delete data.attributes.content;
}

This works but I have a question and a problem with this.

The question: is this an optimal pattern? Is this how it’s best done or are there better solutions?

The problem: when I call the category api and populate articles and again content on articles:

route: /api/categories
query:
{
  fields: ['name'],
  populate: {
    articles: {
      fields: ['title', 'excerpt', 'premium'],
      populate: {
        content: true
      }
    }
  },
}

The content fields on articles gets populated and I don’t want that. I kinda expected that strapi would reuse my custom controllers to query but it does not. How do I solve this? The route api/categories should return articles with title, excerpt, … but not the content field.

I could again filter out the results or remove the populate content query using custom category controllers but that feels wrong. Is there a better way of doing this?