Creating a New 'Review' Content Type
Okay, so now we have a solid understanding on how Strapi exposes data and how we can use the JSON Web Tokens to access certain endpoints that we said are only for people who are authenticated. So let's spice things up a little bit and add a new content type.
I'm going to go to the Content-Type Builder and I'm going to click create new collection type and we're going to create reviews, or actually just 'review'. Okay, so review is going to be our next content type and I'm going to hit continue here. And I'm going to build this up so that we have text, maybe long text for the review, adding another field and that's going to be just a reviewer, so someone who wrote the review. Alright, so that's great. I now have a separate content type.
Establishing a One-to-Many Relationship
I can hit save. But of course, if you think about data modeling a little bit, what we want to achieve is that we want to make sure that a review belongs to a film, right? So that people can actually review films. And in order for us to do that, we need to make sure that we edit the review content type and we build up a relationship between it and the film.
So in light of that, I'm going to add another field and if you scroll down, you will see that there's a relation field here. So I'm going to click that. And if you're familiar with databases and data modeling, then I'm sure you've heard about things like one-to-one, one-to-many, many-to-many relationships. And with this screen, that's exactly what Strapi allows you to set up.
So what I'm going to do, I'm going to select the review film. I'm just going to make the capital F, and I'm going to have the fourth option selected here, which is 'a film has many reviews'. Okay? Because theoretically, if you think about this, we will have one film, and one film can have multiple reviews. So that's exactly what this relationship is going to enable us to do. And this will also reference the reviews field from film. Okay, so there's going to be a field that's going to reference this. So let me just hit finish and hit save. And now we have a film that has a relation with film. Okay, that's perfect.
Adding and Viewing Related Content
Now let's go and see how this looks from the film's perspective. If I go to the film collection type, a 'reviews' appeared here and it says relation with 'review'. And then 'film belongs to many reviews'. Excellent. So let's see how that works in action by going to the Content Manager. And in the Content Manager, I'm going to add a new review. I'm going to press create new entry and I'm going to say 'amazing' and I'm the reviewer. And in the relation, notice that I can select a film that I want to associate this review with. So I'm going to select Star Wars, hit save, and now this review is attached to that film.
On the flip side, if I now go to film, and if I select this film or if I just edit it, notice that I now have a review from me. Awesome. The next question is, how does this look like if we expose this through the API?
Querying and Populating Relational Data
So let's go back to Insomnia. Let's go to films, and let's go to just /api/films for a minute, not sending an authentication token at all, and let's hit send. So by default, as you can see, nothing happens. I still get the information about the films. And there's two reasons why that's happening. Reason number one is because we never exposed the reviews endpoint at all, right? So for reviews, you know, we didn't go to settings, we didn't say that it's publicly available. The other problem is that this is a relation between films and reviews that we've set up, and because there's this relation, we need to explicitly tell Strapi to populate all the relations when we are querying for films. So when we query for films, we essentially want the reviews to be returned as well.
So let's do this step by step. So first, let's go to settings, let's go to roles, let's go and for now just make it public. Okay, so notice that the review content type appears here and I'm going to say 'find' and make that available publicly. Let's just hit save. Go back to Insomnia, hit send. I still don't see that. And this is why I said that you need to tell Strapi to populate all the relations. So how do you do that? You put a question mark in here and then you say populate, and you have two options. You could either specify what you want to populate or you make this equal to asterisk, as opposed to typing in, you know, 'reviews' and whatnot. And this will populate all the relations, and in this case, it will populate reviews. But just FYI, if you have a media content type added, so you have some media files that you want to upload, it is also going to appear just with populate=*.
So I'm going to hit send, and now I have 'reviews' and I have an empty array here. Why is that array empty? Well, let's see if you can figure this out on your own. I'm going to give you a few seconds to think about it, but then I'm going to come back to my content manager, click review, and look at this: it's a draft. We forgot to publish this. So I'm going to hit publish, come back to Insomnia, hit send, and voila! Now I have the data for the review and for the film in one single API call.
Securing Data with Role-Based Permissions
Now what happens, and let's do this as another scenario because this is going to be applicable to the Next.js project. Let's say that we want to have the reviews to be only visible... let me just check... this film is fine, review, okay. For review, I disabled that from public. I'm going to go to authenticated and let me just set this up. And for review, I want 'find'. So this setup is going to be: publicly show me all the films, like so. But if I say populate, what is going to happen? Because I now said that, hey, the reviews should not be available publicly. So if I hit send, notice that you can't trick the authentication model in Strapi. It's not going to populate the data. And so let's see what happens if we take our JSON Web Token, go back to films, send the token and hit send.
And now we get a forbidden. Now that's interesting. Why is that happening? So what's happening is that Strapi is aware of the fact that the review is only visible to authenticated users. However, if you check the films for authenticated users, we didn't enable anything. So what we need to do, we need to explicitly say that for everyone who is authenticated, we want to also be able to run the GET /api/films method, HTTP method. So I'm going to hit save. And once you have that and you hit send, you will now get all this data. Now if I disable the token from being sent, I'm just going to get the films without the reviews. So this is now replicating the functionality that we're going to implement in Next.js as well.