تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Exposing Model Data Risks0:07

All right, so now for this episode, let's take a look at something very serious and very sensitive. Right now we are converting our Eloquent models into JSON and passing that entire payload to the front end. And almost certainly you don't wanna do this, lemme show you if I open up Chrome dev tools, you'll see that I have the View Chrome extension installed. If you're working along and you don't have this, just Google it and pull it in.

If you're working along and you don't have this, just Google it and pull it in. Okay, so now you'll see for our root page component, we are passing through profile and posts. And yeah, once again, you'll see this is just the Eloquent attributes converted into JSON and even if I never reference these values, uh, within our view component, they're still available and they're still exposed to anyone who wants to inspect it. So in this case, I can say, all right,

and they're still exposed to anyone who wants to inspect it. So in this case, I can say, all right, now I know the user's id. Now I know when they created their account. Now I know when they last updated their account, right? And I can do this for every single person in the feed. Now the same is gonna be true for posts. We're just converting all of those attributes to JSON, even if we never represent these or reference these at all. Uh, once again, you almost certainly don't want to do this.

Using JSON Resources1:09

even if we never represent these or reference these at all. Uh, once again, you almost certainly don't want to do this. Instead, we should be explicit about the data that is being passed to our front end. And we can do that by referencing JS resource classes. Let me show you, let's open up PostController. And yet right here, we are automatically converting this to json and sending it to the front end with Inertia. But instead, yeah, I just wanna convert this to a resource class like this.

But instead, yeah, I just wanna convert this to a resource class like this. Now, Laravel does offer a two resource method, but it is going to expect an actual resource class to exist. So if I switch back to the browser, of course we're gonna see an error failed to find a resource class for the model Profile. All right, let's fix that from the terminal. I'm gonna make a new resource and it's gonna be called ProfileResource.

I'm gonna make a new resource and it's gonna be called ProfileResource. All right, so now we have a new resources directory within our HTTP folder. Let's take a look. HTTP resources, ProfileResource. So now within the toArray method, we can be explicit about what's being sent to the front end. And of course, by default it's just converting the model to an array.

And of course, by default it's just converting the model to an array. Okay, so now, uh, mostly this should solve our error, but actually I wanna show you something real quick. If I go back to PostController, let's just return the profile. I want you to see what that looks like by default. And we get an object with all of the attributes. But now notice if I say toResource, it's gonna be in a slightly different shape.

Disabling Data Wrapping2:40

But now notice if I say resource, it's gonna be in a slightly different shape. If I refresh now, yeah, we get the same thing, but it's wrapped within a data object as a standard. So that would mean in your front end you would need to make sure you reference data.handle in this case. Or if you wanna disable that wrapping, you can do so within your AppServiceProvider like this. Let's go into AppServiceProvider. Within the boot method, I can say JsonResource,

Let's go into AppServiceProvider. Within the boot method, I can say JsonResource, I'll import that, and there should be a method called withoutWrapping. All right, and note the full path there. Okay, so now if I switch back, give it a refresh, you'll see we get effectively the same as what we had before. Okay, so now let's return to PostController. I can remove this and of course we're still passing.

Selecting Profile Fields3:22

Okay, so now let's return to PostController. I can remove this and of course we're still passing that full payload, but you'll see we're not breaking anything. Okay, so now we can just sequentially go through here and figure out precisely, uh, what needs to be passed profile, resource. So what we might do is say, well, I know that I need, and what is it? You know, and you might end up doing this.

and what is it? You know, and you might end up doing this. You might go into post index and you're just gonna hunt for every place that you reference your profile. And it looks like we have three references, all right? Yep. So let's go into post form. And at, at the very start, I can see we need the avatar URL. So if nothing else, I'm gonna reference the avatar URL.

I can see we need the avatar, URL. So if nothing else, I'm gonna reference the avatar URL. And actually on this note, I'm gonna turn on cursor tab because this is gonna take just a little bit of time. So I can say this and notice I can access this, but still refer to the profile, uh, object as a mix in that's handled behind the scenes. Real quick, if you wanna see within JsonResource, or maybe this one delegates the resource. Yeah. So right here, if you try to access a value,

or maybe this one delegates the resource. Yeah. So right here, if you try to access a value, it's gonna delegate to the resource, which would be your, um, your Post or your Profile. Anyways, that will be avatarUrl. Okay, so now let's see what tab can do for us. Let's, um, update that. And I think that's mostly okay. Yeah. So at this point we might, uh, switch back to the browser, see if we, uh, encounter any glitches or anything like that.

So at this point we might, uh, switch back to the browser, see if we, uh, encounter any glitches or anything like that. And then I can update this on the go. But nonetheless, even if you're in a situation where it's the exact same attributes as what would be, uh, automatically created, when you convert Eloquent to JS, I would still recommend creating a dedicated resource class just to be explicit and to enforce that only the fields represented in this file will be passed to the front end.

and to enforce that only the fields represented in this file will be passed to the front end and there's no magic or weirdness taking place. Okay? So if I come back and give it a refresh, it looks like everything is okay. So hopefully, um, this should be fine. Alright, so just to test this out, I'm going to return to PostController. And once again, I just wanna see what this created in terms of the actual attributes.

And once again, I just wanna see what this created in terms of the actual attributes. Yeah, so followersCount, all of this is set to know, but I do think Jeremy references some of these. So this is a situation where we may have a default representation for Profile, but then in certain situations we want to add additional attributes. So in those cases, there is an additional method we can use on our resource, or you're allowed

So in those cases, there is an additional method we can use on our resource, or you're allowed to create more than one resource. There's no rule, um, that every Eloquent model must only have one, uh, API resource. No, you, you can have multiple if you need to. So keep that in mind nonetheless. I'm gonna search for followers.count(). And yeah, it looks like in, in Jeremy's original header,

I'm gonna search for followers. Count. And yeah, it looks like in, in Jeremy's original header, he is referencing these, so he's conditionally loading them in certain situations. Alright, we're just gonna keep that in mind. We may decide that these do not need to be included, um, every single time, but on the other hand, maybe they do. So we're just going to add a TODO here to keep an eye on this. Are they needed? We're not sure yet.

Creating Post Resources6:41

to do here to keep an eye on this. Are they needed? We're not sure yet. We're still learning the, um, we're still learning the code base. So if we can get rid of them, we will. Okay, so now we're gonna do the exact same thing for posts. But notice in this case posts, and by the way, let me clear that out. Posts is actually a collection of posts. It's not a single post.

Posts is actually a collection of Posts. It's not a single Post. Nonetheless, I can still say to resource collection, but once again, if I switch back to the browser, give it a refresh, we're gonna see that same error. Now it can't find a resource for a Post. Okay? Once again, make a resource for a Post. All right, let's open up that file. Once again, by default it's just casting the Post to an array.

Once again, by default it's just casting the Post to an array. So that should solve our error if we refresh and now we can be explicit return. Let's see what cursor comes up with. Um, the id, we might need it. We may not, the contents. Let's let all of that come in. All right. And I think that is reasonably okay. Again, I'm trying to learn the code base here, so I might be missing something, but that seems okay.

Again, I'm trying to learn the code base here, so I might be missing something, but that seems okay. And also notice it was smart enough to know, okay, well let's load a profile when a profile relationship is loaded. Otherwise don't do it at all. So this handles situations where you say like, post first versus a post with profile, gimme the first one. In this case, the profile relationship is eager loaded. So we will get a profile and resource,

Adding Like Resource8:14

In this case, the profile relationship is eager loaded. So we will get a profile and resource, but only when it's loaded. If it's excluded, we don't, uh, we don't do that. All right, next, it looks like, um, a Post can have likes. We knew that, but I don't quite know what the relationship is. So he has a dedicated Like model, a Like belongs to a Profile and a Post. Okay? And he's got methods to create a Like

to a profile and a Post. Okay? And he's got methods to create a like and to remove a like, okay. So with that in mind, yeah, maybe we should go ahead and create a resource for that as well. If it's needed, like resource. All right, let's import that like resource will return. I think we need the post id. Yeah, and also the profile id. So you can see why it turned on cursor tab.

I think we need the postId. Yeah, and also the profileId. So you can see why it turned on cursorTab. It definitely saves us a little bit of time. Alright, so now it may even turn out that we don't need this at all. We just need to know if it's liked or not. I'm not entirely sure we will work on that though. So now if I switch back to PostResource, this all seems pretty reasonable to me. Okay, so now if I come back

this all seems pretty reasonable to me. Okay, so now if I come back and refresh, yeah, take a look, we're still gonna see the same thing in the browser. But notice if I inspect this now for profile, this is only the stuff that I'm planning on sending through. And if I take a look at posts, this is only the stuff that I'm explicitly sending through. It's a much safer way to handle this. So on that note, just keep in mind if I go back to profile

It's a much safer way to handle this. So on that note, just keep in mind if I go back to profile and resource, yeah, the more I think about it, maybe these should only be referenced if they, if a likes, um, count was, was loaded. So for example, um, if Jeremy is using a count with counts method, then I believe we could say well load the followers count only when, uh, and we call when counted, and then I can reference the relationship name.

and we call when counted, and then I can reference the relationship name. So I believe that would probably be okay. I think that's how we wanna handle this. So let's see if Cursor can do the rest followings count, post count, yes, something like that. And again, I'm just not even entirely sure if these are being referenced, but if we load those relationships, let's make sure that they are included. All right, so return to PostController.

let's make sure that they are included. All right, so return to PostController. And now we've learned that we can use a resource and resourceCollection method to convert our Eloquent models into the associated API resources.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟